1use std::{
18 collections::{BTreeMap, BTreeSet},
19 sync::Arc,
20};
21
22use assert_matches::assert_matches;
23use matrix_sdk_common::{
24 deserialized_responses::{
25 AlgorithmInfo, DecryptedRoomEvent, EncryptionInfo, TimelineEvent, TimelineEventKind,
26 UnableToDecryptInfo, UnableToDecryptReason, VerificationState,
27 },
28 linked_chunk::{
29 ChunkContent, ChunkIdentifier as CId, LinkedChunkId, Position, Update, lazy_loader,
30 },
31};
32use matrix_sdk_test::{
33 ALICE, DEFAULT_TEST_ROOM_ID,
34 event_factory::{EventBuilder, EventFactory},
35};
36use ruma::{
37 EventId, RoomId, event_id,
38 events::{
39 AnyMessageLikeEvent, AnyTimelineEvent,
40 relation::RelationType,
41 room::message::{RoomMessageEventContent, RoomMessageEventContentWithoutRelation},
42 },
43 push::Action,
44 room_id,
45 serde::Raw,
46};
47use serde_json::{Map, Value};
48use strass::assert_let;
49
50use super::{
51 super::{Gap, thread::ThreadInfo},
52 DEFAULT_CHUNK_CAPACITY, DynEventCacheStore,
53};
54use crate::read_receipts::ReadReceipts;
55
56pub fn make_test_event(room_id: &RoomId, content: &str) -> TimelineEvent {
61 make_test_event_with_event_id(room_id, content, None)
62}
63
64pub fn make_encrypted_test_event(room_id: &RoomId, session_id: &str) -> TimelineEvent {
67 let device_id = "DEVICEID";
68 let builder = EventFactory::new()
69 .encrypted("", "curve_key", device_id, session_id)
70 .room(room_id)
71 .sender(*ALICE);
72
73 let event = builder.into_raw();
74 let utd_info = UnableToDecryptInfo {
75 session_id: Some(session_id.to_owned()),
76 reason: UnableToDecryptReason::MissingMegolmSession { withheld_code: None },
77 };
78
79 TimelineEvent::from_utd(event, utd_info)
80}
81
82pub fn make_test_event_with_event_id(
84 room_id: &RoomId,
85 content: &str,
86 event_id: Option<&EventId>,
87) -> TimelineEvent {
88 let encryption_info = Arc::new(make_encryption_info());
89 let event = make_test_event_builder_with_event_id(room_id, content, event_id).into_raw();
90
91 TimelineEvent::from_decrypted(
92 DecryptedRoomEvent { event, encryption_info, unsigned_encryption_info: None },
93 Some(vec![Action::Notify]),
94 )
95}
96
97pub fn make_test_event_without_event_id(room_id: &RoomId, content: &str) -> TimelineEvent {
99 let encryption_info = Arc::new(make_encryption_info());
100 let event =
101 make_test_event_builder_with_event_id(room_id, content, None).no_event_id().into_raw();
102
103 TimelineEvent::from_decrypted(
104 DecryptedRoomEvent { event, encryption_info, unsigned_encryption_info: None },
105 Some(vec![Action::Notify]),
106 )
107}
108
109pub fn make_test_event_without_event_type(room_id: &RoomId, content: &str) -> TimelineEvent {
111 let encryption_info = Arc::new(make_encryption_info());
112 let raw = make_test_event_builder_with_event_id(room_id, content, None)
113 .into_raw::<AnyTimelineEvent>();
114
115 let mut map = serde_json::from_str::<Map<String, Value>>(raw.into_json().get())
118 .expect("should deserialize raw event");
119 map.remove("type").expect("should have key 'type'");
120 let string = serde_json::to_string(&map).expect("should serialize map");
121 let event = Raw::<AnyTimelineEvent>::from_json_string(string)
122 .expect("should create raw from json string");
123
124 TimelineEvent::from_decrypted(
125 DecryptedRoomEvent { event, encryption_info, unsigned_encryption_info: None },
126 Some(vec![Action::Notify]),
127 )
128}
129
130pub fn make_test_event_builder_with_event_id(
135 room_id: &RoomId,
136 content: &str,
137 event_id: Option<&EventId>,
138) -> EventBuilder<RoomMessageEventContent> {
139 let mut builder = EventFactory::new().text_msg(content).room(room_id).sender(*ALICE);
140 if let Some(event_id) = event_id {
141 builder = builder.event_id(event_id);
142 }
143 builder
144}
145
146pub fn make_encryption_info() -> EncryptionInfo {
151 EncryptionInfo {
152 sender: (*ALICE).into(),
153 sender_device: None,
154 forwarder: None,
155 algorithm_info: AlgorithmInfo::MegolmV1AesSha2 {
156 curve25519_key: "1337".to_owned(),
157 sender_claimed_keys: Default::default(),
158 session_id: Some("mysessionid9".to_owned()),
159 },
160 verification_state: VerificationState::Verified,
161 }
162}
163
164#[track_caller]
169pub fn check_test_event(event: &TimelineEvent, text: &str) {
170 let actions = event.push_actions().unwrap();
172 assert_eq!(actions.len(), 1);
173 assert_matches!(&actions[0], Action::Notify);
174
175 assert_matches!(&event.kind, TimelineEventKind::Decrypted(d) => {
177 assert_eq!(d.encryption_info.sender, *ALICE);
179 assert_matches!(&d.encryption_info.algorithm_info, AlgorithmInfo::MegolmV1AesSha2 { curve25519_key, .. } => {
180 assert_eq!(curve25519_key, "1337");
181 });
182
183 let deserialized = d.event.deserialize().unwrap();
185 assert_matches!(deserialized, AnyTimelineEvent::MessageLike(AnyMessageLikeEvent::RoomMessage(msg)) => {
186 assert_eq!(msg.as_original().unwrap().content.body(), text);
187 });
188 });
189}
190
191#[allow(async_fn_in_trait)]
196pub trait EventCacheStoreIntegrationTests {
197 async fn test_handle_updates_and_rebuild_linked_chunk(&self);
200
201 async fn test_linked_chunk_exists_before_referenced(&self);
204
205 async fn test_linked_chunk_allows_same_event_in_room_and_thread(&self);
208
209 async fn test_load_last_chunk(&self);
211
212 async fn test_load_last_chunk_with_a_cycle(&self);
215
216 async fn test_load_previous_chunk(&self);
218
219 async fn test_linked_chunk_incremental_loading(&self);
222
223 async fn test_linked_chunk_remove_chunk(&self);
225
226 async fn test_linked_chunk_push_items(&self);
228
229 async fn test_linked_chunk_replace_item(&self);
231
232 async fn test_linked_chunk_filter_incomplete_events(&self);
235
236 async fn test_linked_chunk_remove_item(&self);
238
239 async fn test_linked_chunk_detach_last_items(&self);
241
242 async fn test_linked_chunk_start_end_reattach_items(&self);
244
245 async fn test_linked_chunk_clear(&self);
247
248 async fn test_linked_chunk_clear_and_reinsert(&self);
250
251 async fn test_rebuild_empty_linked_chunk(&self);
254
255 async fn test_linked_chunk_multiple_rooms(&self);
258
259 async fn test_load_all_chunks_metadata(&self);
261
262 async fn test_load_and_update_thread_info(&self);
264
265 async fn test_clear_all_events(&self);
267
268 async fn test_clear_all_events_for_specific_room(&self);
270
271 async fn test_filter_duplicated_events(&self);
273
274 async fn test_filter_duplicate_events_no_events(&self);
276
277 async fn test_find_event(&self);
279
280 async fn test_find_event_when_event_in_room_and_thread(&self);
283
284 async fn test_find_event_relations(&self);
286
287 async fn test_find_event_relations_when_event_in_room_and_thread(&self);
290
291 async fn test_get_room_events(&self);
293
294 async fn test_get_room_events_filtered(&self);
296
297 async fn test_get_room_events_with_event_in_room_and_thread(&self);
300
301 async fn test_save_event(&self);
303
304 async fn test_save_event_updates_event_in_room_and_thread(&self);
307
308 async fn test_thread_vs_room_linked_chunk(&self);
311}
312
313impl EventCacheStoreIntegrationTests for DynEventCacheStore {
314 async fn test_handle_updates_and_rebuild_linked_chunk(&self) {
315 let room_id = room_id!("!r0:matrix.org");
316 let linked_chunk_id = LinkedChunkId::Room(room_id);
317
318 self.handle_linked_chunk_updates(
319 linked_chunk_id,
320 vec![
321 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
323 Update::PushItems {
325 at: Position::new(CId::new(0), 0),
326 items: vec![
327 make_test_event(room_id, "hello"),
328 make_test_event(room_id, "world"),
329 ],
330 },
331 Update::NewGapChunk {
333 previous: Some(CId::new(0)),
334 new: CId::new(1),
335 next: None,
336 gap: Gap { token: "parmesan".to_owned() },
337 },
338 Update::NewItemsChunk { previous: Some(CId::new(1)), new: CId::new(2), next: None },
340 Update::PushItems {
342 at: Position::new(CId::new(2), 0),
343 items: vec![make_test_event(room_id, "sup")],
344 },
345 ],
346 )
347 .await
348 .unwrap();
349
350 let lc = lazy_loader::from_all_chunks::<3, _, _>(
352 self.load_all_chunks(linked_chunk_id).await.unwrap(),
353 )
354 .unwrap()
355 .unwrap();
356
357 let mut chunks = lc.chunks();
358
359 {
360 let first = chunks.next().unwrap();
361 assert_eq!(first.identifier(), CId::new(0));
364
365 assert_matches!(first.content(), ChunkContent::Items(events) => {
366 assert_eq!(events.len(), 2);
367 check_test_event(&events[0], "hello");
368 check_test_event(&events[1], "world");
369 });
370 }
371
372 {
373 let second = chunks.next().unwrap();
374 assert_eq!(second.identifier(), CId::new(1));
375
376 assert_matches!(second.content(), ChunkContent::Gap(gap) => {
377 assert_eq!(gap.token, "parmesan");
378 });
379 }
380
381 {
382 let third = chunks.next().unwrap();
383 assert_eq!(third.identifier(), CId::new(2));
384
385 assert_matches!(third.content(), ChunkContent::Items(events) => {
386 assert_eq!(events.len(), 1);
387 check_test_event(&events[0], "sup");
388 });
389 }
390
391 assert!(chunks.next().is_none());
392 }
393
394 async fn test_linked_chunk_exists_before_referenced(&self) {
395 let room_id = *DEFAULT_TEST_ROOM_ID;
396 let linked_chunk_id = LinkedChunkId::Room(room_id);
397
398 self.handle_linked_chunk_updates(
400 linked_chunk_id,
401 vec![Update::NewItemsChunk {
402 previous: Some(CId::new(41)),
403 new: CId::new(42),
404 next: None,
405 }],
406 )
407 .await
408 .unwrap_err();
409
410 self.handle_linked_chunk_updates(
412 linked_chunk_id,
413 vec![Update::NewItemsChunk {
414 previous: None,
415 new: CId::new(42),
416 next: Some(CId::new(43)),
417 }],
418 )
419 .await
420 .unwrap_err();
421
422 self.handle_linked_chunk_updates(
424 linked_chunk_id,
425 vec![Update::NewGapChunk {
426 previous: Some(CId::new(41)),
427 new: CId::new(42),
428 next: None,
429 gap: Gap { token: "gap".to_owned() },
430 }],
431 )
432 .await
433 .unwrap_err();
434
435 self.handle_linked_chunk_updates(
437 linked_chunk_id,
438 vec![Update::NewGapChunk {
439 previous: None,
440 new: CId::new(42),
441 next: Some(CId::new(43)),
442 gap: Gap { token: "gap".to_owned() },
443 }],
444 )
445 .await
446 .unwrap_err();
447 }
448
449 async fn test_linked_chunk_allows_same_event_in_room_and_thread(&self) {
450 let room_id = *DEFAULT_TEST_ROOM_ID;
456 let thread_root = event_id!("$thread_root");
457
458 let event_id = event_id!("$thread_reply");
461 let event = make_test_event_with_event_id(room_id, "thread reply", Some(event_id));
462
463 let room_linked_chunk_id = LinkedChunkId::Room(room_id);
464 let thread_linked_chunk_id = LinkedChunkId::Thread(room_id, thread_root);
465
466 self.handle_linked_chunk_updates(
468 room_linked_chunk_id,
469 vec![
470 Update::NewItemsChunk { previous: None, new: CId::new(1), next: None },
471 Update::PushItems { at: Position::new(CId::new(1), 0), items: vec![event.clone()] },
472 ],
473 )
474 .await
475 .unwrap();
476
477 self.handle_linked_chunk_updates(
479 thread_linked_chunk_id,
480 vec![
481 Update::NewItemsChunk { previous: None, new: CId::new(1), next: None },
482 Update::PushItems { at: Position::new(CId::new(1), 0), items: vec![event] },
483 ],
484 )
485 .await
486 .unwrap();
487
488 let room_chunks = self.load_all_chunks(room_linked_chunk_id).await.unwrap();
491 let thread_chunks = self.load_all_chunks(thread_linked_chunk_id).await.unwrap();
492
493 assert_eq!(room_chunks.len(), 1);
494 assert_eq!(thread_chunks.len(), 1);
495
496 assert_matches!(&room_chunks[0].content, ChunkContent::Items(events) => {
498 assert_eq!(events.len(), 1);
499 assert_eq!(events[0].event_id(), Some(event_id));
500 });
501 assert_matches!(&thread_chunks[0].content, ChunkContent::Items(events) => {
502 assert_eq!(events.len(), 1);
503 assert_eq!(events[0].event_id(), Some(event_id));
504 });
505 }
506
507 async fn test_load_all_chunks_metadata(&self) {
508 let room_id = room_id!("!r0:matrix.org");
509 let linked_chunk_id = LinkedChunkId::Room(room_id);
510
511 self.handle_linked_chunk_updates(
512 linked_chunk_id,
513 vec![
514 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
516 Update::PushItems {
518 at: Position::new(CId::new(0), 0),
519 items: vec![
520 make_test_event(room_id, "hello"),
521 make_test_event(room_id, "world"),
522 ],
523 },
524 Update::NewGapChunk {
526 previous: Some(CId::new(0)),
527 new: CId::new(1),
528 next: None,
529 gap: Gap { token: "parmesan".to_owned() },
530 },
531 Update::NewItemsChunk { previous: Some(CId::new(1)), new: CId::new(2), next: None },
533 Update::PushItems {
535 at: Position::new(CId::new(2), 0),
536 items: vec![make_test_event(room_id, "sup")],
537 },
538 Update::NewItemsChunk { previous: Some(CId::new(2)), new: CId::new(3), next: None },
540 ],
541 )
542 .await
543 .unwrap();
544
545 let metas = self.load_all_chunks_metadata(linked_chunk_id).await.unwrap();
546 assert_eq!(metas.len(), 4);
547
548 assert_eq!(metas[0].identifier, CId::new(0));
550 assert_eq!(metas[0].previous, None);
551 assert_eq!(metas[0].next, Some(CId::new(1)));
552 assert_eq!(metas[0].num_items, 2);
553
554 assert_eq!(metas[1].identifier, CId::new(1));
556 assert_eq!(metas[1].previous, Some(CId::new(0)));
557 assert_eq!(metas[1].next, Some(CId::new(2)));
558 assert_eq!(metas[1].num_items, 0);
559
560 assert_eq!(metas[2].identifier, CId::new(2));
562 assert_eq!(metas[2].previous, Some(CId::new(1)));
563 assert_eq!(metas[2].next, Some(CId::new(3)));
564 assert_eq!(metas[2].num_items, 1);
565
566 assert_eq!(metas[3].identifier, CId::new(3));
568 assert_eq!(metas[3].previous, Some(CId::new(2)));
569 assert_eq!(metas[3].next, None);
570 assert_eq!(metas[3].num_items, 0);
571 }
572
573 async fn test_load_last_chunk(&self) {
574 let room_id = room_id!("!r0:matrix.org");
575 let linked_chunk_id = LinkedChunkId::Room(room_id);
576 let event = |msg: &str| make_test_event(room_id, msg);
577
578 {
580 let (last_chunk, chunk_identifier_generator) =
581 self.load_last_chunk(linked_chunk_id).await.unwrap();
582
583 assert!(last_chunk.is_none());
584 assert_eq!(chunk_identifier_generator.current(), 0);
585 }
586
587 {
589 self.handle_linked_chunk_updates(
590 linked_chunk_id,
591 vec![
592 Update::NewItemsChunk { previous: None, new: CId::new(42), next: None },
593 Update::PushItems {
594 at: Position::new(CId::new(42), 0),
595 items: vec![event("saucisse de morteau"), event("comté")],
596 },
597 ],
598 )
599 .await
600 .unwrap();
601
602 let (last_chunk, chunk_identifier_generator) =
603 self.load_last_chunk(linked_chunk_id).await.unwrap();
604
605 assert_matches!(last_chunk, Some(last_chunk) => {
606 assert_eq!(last_chunk.identifier, 42);
607 assert!(last_chunk.previous.is_none());
608 assert!(last_chunk.next.is_none());
609 assert_matches!(last_chunk.content, ChunkContent::Items(items) => {
610 assert_eq!(items.len(), 2);
611 check_test_event(&items[0], "saucisse de morteau");
612 check_test_event(&items[1], "comté");
613 });
614 });
615 assert_eq!(chunk_identifier_generator.current(), 42);
616 }
617
618 {
620 self.handle_linked_chunk_updates(
621 linked_chunk_id,
622 vec![
623 Update::NewItemsChunk {
624 previous: Some(CId::new(42)),
625 new: CId::new(7),
626 next: None,
627 },
628 Update::PushItems {
629 at: Position::new(CId::new(7), 0),
630 items: vec![event("fondue"), event("gruyère"), event("mont d'or")],
631 },
632 ],
633 )
634 .await
635 .unwrap();
636
637 let (last_chunk, chunk_identifier_generator) =
638 self.load_last_chunk(linked_chunk_id).await.unwrap();
639
640 assert_matches!(last_chunk, Some(last_chunk) => {
641 assert_eq!(last_chunk.identifier, 7);
642 assert_matches!(last_chunk.previous, Some(previous) => {
643 assert_eq!(previous, 42);
644 });
645 assert!(last_chunk.next.is_none());
646 assert_matches!(last_chunk.content, ChunkContent::Items(items) => {
647 assert_eq!(items.len(), 3);
648 check_test_event(&items[0], "fondue");
649 check_test_event(&items[1], "gruyère");
650 check_test_event(&items[2], "mont d'or");
651 });
652 });
653 assert_eq!(chunk_identifier_generator.current(), 42);
654 }
655 }
656
657 async fn test_load_last_chunk_with_a_cycle(&self) {
658 let room_id = room_id!("!r0:matrix.org");
659 let linked_chunk_id = LinkedChunkId::Room(room_id);
660
661 self.handle_linked_chunk_updates(
662 linked_chunk_id,
663 vec![
664 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
665 Update::NewItemsChunk {
666 previous: Some(CId::new(0)),
671 new: CId::new(1),
672 next: Some(CId::new(0)),
673 },
674 ],
675 )
676 .await
677 .unwrap();
678
679 self.load_last_chunk(linked_chunk_id).await.unwrap_err();
680 }
681
682 async fn test_load_previous_chunk(&self) {
683 let room_id = room_id!("!r0:matrix.org");
684 let linked_chunk_id = LinkedChunkId::Room(room_id);
685 let event = |msg: &str| make_test_event(room_id, msg);
686
687 {
690 let previous_chunk =
691 self.load_previous_chunk(linked_chunk_id, CId::new(153)).await.unwrap();
692
693 assert!(previous_chunk.is_none());
694 }
695
696 {
699 self.handle_linked_chunk_updates(
700 linked_chunk_id,
701 vec![Update::NewItemsChunk { previous: None, new: CId::new(42), next: None }],
702 )
703 .await
704 .unwrap();
705
706 let previous_chunk =
707 self.load_previous_chunk(linked_chunk_id, CId::new(42)).await.unwrap();
708
709 assert!(previous_chunk.is_none());
710 }
711
712 {
714 self.handle_linked_chunk_updates(
715 linked_chunk_id,
716 vec![
717 Update::NewItemsChunk {
719 previous: None,
720 new: CId::new(7),
721 next: Some(CId::new(42)),
722 },
723 Update::PushItems {
724 at: Position::new(CId::new(7), 0),
725 items: vec![event("brigand du jorat"), event("morbier")],
726 },
727 ],
728 )
729 .await
730 .unwrap();
731
732 let previous_chunk =
733 self.load_previous_chunk(linked_chunk_id, CId::new(42)).await.unwrap();
734
735 assert_matches!(previous_chunk, Some(previous_chunk) => {
736 assert_eq!(previous_chunk.identifier, 7);
737 assert!(previous_chunk.previous.is_none());
738 assert_matches!(previous_chunk.next, Some(next) => {
739 assert_eq!(next, 42);
740 });
741 assert_matches!(previous_chunk.content, ChunkContent::Items(items) => {
742 assert_eq!(items.len(), 2);
743 check_test_event(&items[0], "brigand du jorat");
744 check_test_event(&items[1], "morbier");
745 });
746 });
747 }
748 }
749
750 async fn test_linked_chunk_incremental_loading(&self) {
751 let room_id = room_id!("!r0:matrix.org");
752 let linked_chunk_id = LinkedChunkId::Room(room_id);
753 let event = |msg: &str| make_test_event(room_id, msg);
754
755 {
757 let (last_chunk, chunk_identifier_generator) =
758 self.load_last_chunk(linked_chunk_id).await.unwrap();
759
760 assert!(last_chunk.is_none());
761 assert_eq!(chunk_identifier_generator.current(), 0);
762 }
763
764 self.handle_linked_chunk_updates(
765 linked_chunk_id,
766 vec![
767 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
769 Update::PushItems {
771 at: Position::new(CId::new(0), 0),
772 items: vec![event("a"), event("b")],
773 },
774 Update::NewGapChunk {
776 previous: Some(CId::new(0)),
777 new: CId::new(1),
778 next: None,
779 gap: Gap { token: "morbier".to_owned() },
780 },
781 Update::NewItemsChunk { previous: Some(CId::new(1)), new: CId::new(2), next: None },
783 Update::PushItems {
785 at: Position::new(CId::new(2), 0),
786 items: vec![event("c"), event("d"), event("e")],
787 },
788 ],
789 )
790 .await
791 .unwrap();
792
793 let mut linked_chunk = {
795 let (last_chunk, chunk_identifier_generator) =
796 self.load_last_chunk(linked_chunk_id).await.unwrap();
797
798 assert_eq!(chunk_identifier_generator.current(), 2);
799
800 let linked_chunk = lazy_loader::from_last_chunk::<DEFAULT_CHUNK_CAPACITY, _, _>(
801 last_chunk,
802 chunk_identifier_generator,
803 )
804 .unwrap() .unwrap(); let mut rchunks = linked_chunk.rchunks();
808
809 assert_matches!(rchunks.next(), Some(chunk) => {
811 assert_eq!(chunk.identifier(), 2);
812 assert_eq!(chunk.lazy_previous(), Some(CId::new(1)));
813
814 assert_matches!(chunk.content(), ChunkContent::Items(events) => {
815 assert_eq!(events.len(), 3);
816 check_test_event(&events[0], "c");
817 check_test_event(&events[1], "d");
818 check_test_event(&events[2], "e");
819 });
820 });
821
822 assert!(rchunks.next().is_none());
823
824 linked_chunk
825 };
826
827 {
829 let first_chunk = linked_chunk.chunks().next().unwrap().identifier();
830 let previous_chunk =
831 self.load_previous_chunk(linked_chunk_id, first_chunk).await.unwrap().unwrap();
832
833 lazy_loader::insert_new_first_chunk(&mut linked_chunk, previous_chunk).unwrap();
834
835 let mut rchunks = linked_chunk.rchunks();
836
837 assert_matches!(rchunks.next(), Some(chunk) => {
839 assert_eq!(chunk.identifier(), 2);
840 assert!(chunk.lazy_previous().is_none());
841
842 assert_matches!(chunk.content(), ChunkContent::Items(events) => {
844 assert_eq!(events.len(), 3);
845 check_test_event(&events[0], "c");
846 check_test_event(&events[1], "d");
847 check_test_event(&events[2], "e");
848 });
849 });
850
851 assert_matches!(rchunks.next(), Some(chunk) => {
853 assert_eq!(chunk.identifier(), 1);
854 assert_eq!(chunk.lazy_previous(), Some(CId::new(0)));
855
856 assert_matches!(chunk.content(), ChunkContent::Gap(gap) => {
857 assert_eq!(gap.token, "morbier");
858 });
859 });
860
861 assert!(rchunks.next().is_none());
862 }
863
864 {
866 let first_chunk = linked_chunk.chunks().next().unwrap().identifier();
867 let previous_chunk =
868 self.load_previous_chunk(linked_chunk_id, first_chunk).await.unwrap().unwrap();
869
870 lazy_loader::insert_new_first_chunk(&mut linked_chunk, previous_chunk).unwrap();
871
872 let mut rchunks = linked_chunk.rchunks();
873
874 assert_matches!(rchunks.next(), Some(chunk) => {
876 assert_eq!(chunk.identifier(), 2);
877 assert!(chunk.lazy_previous().is_none());
878
879 assert_matches!(chunk.content(), ChunkContent::Items(events) => {
881 assert_eq!(events.len(), 3);
882 check_test_event(&events[0], "c");
883 check_test_event(&events[1], "d");
884 check_test_event(&events[2], "e");
885 });
886 });
887
888 assert_matches!(rchunks.next(), Some(chunk) => {
890 assert_eq!(chunk.identifier(), 1);
891 assert!(chunk.lazy_previous().is_none());
892
893 assert_matches!(chunk.content(), ChunkContent::Gap(gap) => {
895 assert_eq!(gap.token, "morbier");
896 });
897 });
898
899 assert_matches!(rchunks.next(), Some(chunk) => {
901 assert_eq!(chunk.identifier(), 0);
902 assert!(chunk.lazy_previous().is_none());
903
904 assert_matches!(chunk.content(), ChunkContent::Items(events) => {
905 assert_eq!(events.len(), 2);
906 check_test_event(&events[0], "a");
907 check_test_event(&events[1], "b");
908 });
909 });
910
911 assert!(rchunks.next().is_none());
912 }
913
914 {
916 let first_chunk = linked_chunk.chunks().next().unwrap().identifier();
917 let previous_chunk =
918 self.load_previous_chunk(linked_chunk_id, first_chunk).await.unwrap();
919
920 assert!(previous_chunk.is_none());
921 }
922
923 {
926 let mut chunks = linked_chunk.chunks();
927
928 assert_matches!(chunks.next(), Some(chunk) => {
930 assert_eq!(chunk.identifier(), 0);
931 assert!(chunk.lazy_previous().is_none());
932
933 assert_matches!(chunk.content(), ChunkContent::Items(events) => {
934 assert_eq!(events.len(), 2);
935 check_test_event(&events[0], "a");
936 check_test_event(&events[1], "b");
937 });
938 });
939
940 assert_matches!(chunks.next(), Some(chunk) => {
942 assert_eq!(chunk.identifier(), 1);
943 assert!(chunk.lazy_previous().is_none());
944
945 assert_matches!(chunk.content(), ChunkContent::Gap(gap) => {
946 assert_eq!(gap.token, "morbier");
947 });
948 });
949
950 assert_matches!(chunks.next(), Some(chunk) => {
952 assert_eq!(chunk.identifier(), 2);
953 assert!(chunk.lazy_previous().is_none());
954
955 assert_matches!(chunk.content(), ChunkContent::Items(events) => {
956 assert_eq!(events.len(), 3);
957 check_test_event(&events[0], "c");
958 check_test_event(&events[1], "d");
959 check_test_event(&events[2], "e");
960 });
961 });
962
963 assert!(chunks.next().is_none());
964 }
965 }
966
967 async fn test_linked_chunk_remove_chunk(&self) {
968 let room_id = &DEFAULT_TEST_ROOM_ID;
969 let linked_chunk_id = LinkedChunkId::Room(room_id);
970
971 self.handle_linked_chunk_updates(
972 linked_chunk_id,
973 vec![
974 Update::NewGapChunk {
975 previous: None,
976 new: CId::new(42),
977 next: None,
978 gap: Gap { token: "raclette".to_owned() },
979 },
980 Update::NewGapChunk {
981 previous: Some(CId::new(42)),
982 new: CId::new(43),
983 next: None,
984 gap: Gap { token: "fondue".to_owned() },
985 },
986 Update::NewGapChunk {
987 previous: Some(CId::new(43)),
988 new: CId::new(44),
989 next: None,
990 gap: Gap { token: "tartiflette".to_owned() },
991 },
992 Update::RemoveChunk(CId::new(43)),
993 ],
994 )
995 .await
996 .unwrap();
997
998 let mut chunks = self.load_all_chunks(linked_chunk_id).await.unwrap();
999
1000 assert_eq!(chunks.len(), 2);
1001
1002 let c = chunks.remove(0);
1004 assert_eq!(c.identifier, CId::new(42));
1005 assert_eq!(c.previous, None);
1006 assert_eq!(c.next, Some(CId::new(44)));
1007 assert_matches!(c.content, ChunkContent::Gap(gap) => {
1008 assert_eq!(gap.token, "raclette");
1009 });
1010
1011 let c = chunks.remove(0);
1012 assert_eq!(c.identifier, CId::new(44));
1013 assert_eq!(c.previous, Some(CId::new(42)));
1014 assert_eq!(c.next, None);
1015 assert_matches!(c.content, ChunkContent::Gap(gap) => {
1016 assert_eq!(gap.token, "tartiflette");
1017 });
1018 }
1019
1020 async fn test_linked_chunk_push_items(&self) {
1021 let room_id = *DEFAULT_TEST_ROOM_ID;
1022
1023 let linked_chunk_ids = [
1025 LinkedChunkId::Room(room_id),
1026 LinkedChunkId::Thread(room_id, event_id!("$thread_root")),
1027 LinkedChunkId::PinnedEvents(room_id),
1028 LinkedChunkId::EventFocused(room_id, event_id!("$focus_root")),
1029 ];
1030
1031 let event_id_a = event_id!("$a");
1033 let event_a = make_test_event_with_event_id(room_id, "a", Some(event_id_a));
1034 for linked_chunk_id in linked_chunk_ids {
1035 self.handle_linked_chunk_updates(
1036 linked_chunk_id,
1037 vec![
1038 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
1039 Update::PushItems {
1040 at: Position::new(CId::new(0), 0),
1041 items: vec![event_a.clone()],
1042 },
1043 ],
1044 )
1045 .await
1046 .unwrap();
1047
1048 let mut chunks = self.load_all_chunks(linked_chunk_id).await.unwrap();
1049 assert_eq!(chunks.len(), 1);
1050 let chunk = chunks.remove(0);
1051 assert_matches!(chunk.content, ChunkContent::Items(events) => {
1052 assert_eq!(events.len(), 1);
1053 check_test_event(&events[0], "a");
1054 });
1055 }
1056
1057 let event_b = make_test_event_with_event_id(room_id, "b", Some(event_id!("$b")));
1058 for linked_chunk_id in linked_chunk_ids {
1061 self.handle_linked_chunk_updates(
1062 linked_chunk_id,
1063 vec![Update::PushItems {
1064 at: Position::new(CId::new(0), 0),
1065 items: vec![event_b.clone()],
1066 }],
1067 )
1068 .await
1069 .expect_err("should fail to push an event to an occupied position");
1070
1071 let mut chunks = self.load_all_chunks(linked_chunk_id).await.unwrap();
1072 assert_eq!(chunks.len(), 1);
1073 let chunk = chunks.remove(0);
1074 assert_matches!(chunk.content, ChunkContent::Items(events) => {
1075 assert_eq!(events.len(), 1);
1076 check_test_event(&events[0], "a");
1077 });
1078 }
1079
1080 for linked_chunk_id in linked_chunk_ids {
1083 self.handle_linked_chunk_updates(
1084 linked_chunk_id,
1085 vec![Update::PushItems {
1086 at: Position::new(CId::new(0), 1),
1087 items: vec![event_b.clone()],
1088 }],
1089 )
1090 .await
1091 .unwrap();
1092
1093 let mut chunks = self.load_all_chunks(linked_chunk_id).await.unwrap();
1094 assert_eq!(chunks.len(), 1);
1095 let chunk = chunks.remove(0);
1096 assert_matches!(chunk.content, ChunkContent::Items(events) => {
1097 assert_eq!(events.len(), 2);
1098 check_test_event(&events[0], "a");
1099 check_test_event(&events[1], "b");
1100 });
1101 }
1102
1103 let updated_event_a = make_test_event_with_event_id(room_id, "updated_a", Some(event_id_a));
1105
1106 for linked_chunk_id in linked_chunk_ids {
1109 self.handle_linked_chunk_updates(
1110 linked_chunk_id,
1111 vec![Update::PushItems {
1112 at: Position::new(CId::new(0), 0),
1113 items: vec![updated_event_a.clone()],
1114 }],
1115 )
1116 .await
1117 .expect_err("should fail to push an event to an occupied position");
1118
1119 let mut chunks = self.load_all_chunks(linked_chunk_id).await.unwrap();
1120 assert_eq!(chunks.len(), 1);
1121 let chunk = chunks.remove(0);
1122 assert_matches!(chunk.content, ChunkContent::Items(events) => {
1123 assert_eq!(events.len(), 2);
1124 check_test_event(&events[0], "a");
1125 check_test_event(&events[1], "b");
1126 });
1127 }
1128
1129 for linked_chunk_id in linked_chunk_ids {
1132 self.handle_linked_chunk_updates(
1133 linked_chunk_id,
1134 vec![Update::PushItems {
1135 at: Position::new(CId::new(0), 1),
1136 items: vec![updated_event_a.clone()],
1137 }],
1138 )
1139 .await
1140 .expect_err("should fail to push an event to an occupied position");
1141
1142 let mut chunks = self.load_all_chunks(linked_chunk_id).await.unwrap();
1143 assert_eq!(chunks.len(), 1);
1144 let chunk = chunks.remove(0);
1145 assert_matches!(chunk.content, ChunkContent::Items(events) => {
1146 assert_eq!(events.len(), 2);
1147 check_test_event(&events[0], "a");
1148 check_test_event(&events[1], "b");
1149 });
1150 }
1151
1152 for linked_chunk_id in linked_chunk_ids {
1155 self.handle_linked_chunk_updates(
1156 linked_chunk_id,
1157 vec![Update::PushItems {
1158 at: Position::new(CId::new(0), 2),
1159 items: vec![updated_event_a.clone()],
1160 }],
1161 )
1162 .await
1163 .expect_err("should fail to push an event that already exists in the linked chunk");
1164
1165 let mut chunks = self.load_all_chunks(linked_chunk_id).await.unwrap();
1166 assert_eq!(chunks.len(), 1);
1167 let chunk = chunks.remove(0);
1168 assert_matches!(chunk.content, ChunkContent::Items(events) => {
1169 assert_eq!(events.len(), 2);
1170 check_test_event(&events[0], "a");
1171 check_test_event(&events[1], "b");
1172 });
1173 }
1174
1175 let other_linked_chunk_id = LinkedChunkId::Room(room_id!("!other_room:localhost"));
1177 self.handle_linked_chunk_updates(
1178 other_linked_chunk_id,
1179 vec![Update::NewItemsChunk { previous: None, new: CId::new(0), next: None }],
1180 )
1181 .await
1182 .unwrap();
1183
1184 self.handle_linked_chunk_updates(
1188 other_linked_chunk_id,
1189 vec![Update::PushItems {
1190 at: Position::new(CId::new(0), 0),
1191 items: vec![updated_event_a.clone()],
1192 }],
1193 )
1194 .await
1195 .unwrap();
1196
1197 let mut chunks = self.load_all_chunks(other_linked_chunk_id).await.unwrap();
1198 assert_eq!(chunks.len(), 1);
1199 let chunk = chunks.remove(0);
1200 assert_matches!(chunk.content, ChunkContent::Items(events) => {
1201 assert_eq!(events.len(), 1);
1202 check_test_event(&events[0], "updated_a");
1203 });
1204
1205 for linked_chunk_id in linked_chunk_ids {
1206 let mut chunks = self.load_all_chunks(linked_chunk_id).await.unwrap();
1207 assert_eq!(chunks.len(), 1);
1208 let chunk = chunks.remove(0);
1209 assert_matches!(chunk.content, ChunkContent::Items(events) => {
1210 assert_eq!(events.len(), 2);
1211 check_test_event(&events[0], "updated_a");
1212 check_test_event(&events[1], "b");
1213 });
1214 }
1215 }
1216
1217 async fn test_linked_chunk_replace_item(&self) {
1218 let room_id = &DEFAULT_TEST_ROOM_ID;
1219
1220 let linked_chunk_ids = [
1223 LinkedChunkId::Room(room_id),
1224 LinkedChunkId::Thread(room_id, event_id!("$thread_root")),
1225 LinkedChunkId::PinnedEvents(room_id),
1226 LinkedChunkId::EventFocused(room_id, event_id!("$focus_root")),
1227 LinkedChunkId::Room(room_id!("!other_room")),
1228 ];
1229
1230 let event_id = event_id!("$world");
1232
1233 for linked_chunk_id in linked_chunk_ids {
1235 self.handle_linked_chunk_updates(
1236 linked_chunk_id,
1237 vec![
1238 Update::NewItemsChunk { previous: None, new: CId::new(42), next: None },
1239 Update::PushItems {
1240 at: Position::new(CId::new(42), 0),
1241 items: vec![
1242 make_test_event(room_id, "hello"),
1243 make_test_event_with_event_id(room_id, "world", Some(event_id)),
1244 ],
1245 },
1246 ],
1247 )
1248 .await
1249 .unwrap();
1250
1251 let mut chunks = self.load_all_chunks(linked_chunk_id).await.unwrap();
1252
1253 assert_eq!(chunks.len(), 1);
1254
1255 let c = chunks.remove(0);
1256 assert_eq!(c.identifier, CId::new(42));
1257 assert_eq!(c.previous, None);
1258 assert_eq!(c.next, None);
1259 assert_matches!(c.content, ChunkContent::Items(events) => {
1260 assert_eq!(events.len(), 2);
1261 check_test_event(&events[0], "hello");
1262 check_test_event(&events[1], "world");
1263 });
1264 }
1265
1266 self.handle_linked_chunk_updates(
1269 linked_chunk_ids[0],
1270 vec![Update::ReplaceItem {
1271 at: Position::new(CId::new(42), 1),
1272 item: make_test_event_with_event_id(room_id, "yolo", Some(event_id)),
1273 }],
1274 )
1275 .await
1276 .unwrap();
1277
1278 for linked_chunk_id in linked_chunk_ids {
1280 let mut chunks = self.load_all_chunks(linked_chunk_id).await.unwrap();
1281
1282 assert_eq!(chunks.len(), 1);
1283
1284 let c = chunks.remove(0);
1285 assert_eq!(c.identifier, CId::new(42));
1286 assert_eq!(c.previous, None);
1287 assert_eq!(c.next, None);
1288 assert_matches!(c.content, ChunkContent::Items(events) => {
1289 assert_eq!(events.len(), 2);
1290 check_test_event(&events[0], "hello");
1291 check_test_event(&events[1], "yolo");
1292 });
1293 }
1294 }
1295
1296 async fn test_linked_chunk_filter_incomplete_events(&self) {
1297 let room_id = &DEFAULT_TEST_ROOM_ID;
1298 let linked_chunk_id = LinkedChunkId::Room(room_id);
1299
1300 let event = make_test_event(room_id, "event");
1301 assert_matches!(event.event_id(), Some(_));
1302 assert_matches!(event.kind.event_type(), Some(_));
1303
1304 let event_without_id = make_test_event_without_event_id(room_id, "event-without-id");
1305 assert_eq!(event_without_id.event_id(), None);
1306 assert_matches!(event.kind.event_type(), Some(_));
1307
1308 let event_without_event_type =
1309 make_test_event_without_event_type(room_id, "event-without-event-type");
1310 assert_matches!(event_without_event_type.event_id(), Some(_));
1311 assert_eq!(event_without_event_type.kind.event_type(), None);
1312
1313 self.handle_linked_chunk_updates(
1314 linked_chunk_id,
1315 vec![
1316 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
1317 Update::PushItems {
1318 at: Position::new(CId::new(0), 0),
1319 items: vec![event, event_without_id.clone(), event_without_event_type.clone()],
1320 },
1321 ],
1322 )
1323 .await
1324 .unwrap();
1325
1326 let mut chunks = self.load_all_chunks(linked_chunk_id).await.unwrap();
1327 assert_eq!(chunks.len(), 1);
1328 let c = chunks.remove(0);
1329 assert_eq!(c.identifier, CId::new(0));
1330 assert_eq!(c.previous, None);
1331 assert_eq!(c.next, None);
1332 assert_matches!(c.content, ChunkContent::Items(events) => {
1333 assert_eq!(events.len(), 1);
1334 check_test_event(&events[0], "event");
1335 });
1336
1337 for event in [event_without_id, event_without_event_type] {
1338 self.handle_linked_chunk_updates(
1339 linked_chunk_id,
1340 vec![Update::ReplaceItem { at: Position::new(CId::new(0), 0), item: event }],
1341 )
1342 .await
1343 .unwrap();
1344
1345 let mut chunks = self.load_all_chunks(linked_chunk_id).await.unwrap();
1346 assert_eq!(chunks.len(), 1);
1347 let c = chunks.remove(0);
1348 assert_eq!(c.identifier, CId::new(0));
1349 assert_eq!(c.previous, None);
1350 assert_eq!(c.next, None);
1351 assert_matches!(c.content, ChunkContent::Items(events) => {
1352 assert_eq!(events.len(), 1);
1353 check_test_event(&events[0], "event");
1354 });
1355 }
1356 }
1357
1358 async fn test_linked_chunk_remove_item(&self) {
1359 let room_id = *DEFAULT_TEST_ROOM_ID;
1360 let linked_chunk_id = LinkedChunkId::Room(room_id);
1361
1362 self.handle_linked_chunk_updates(
1363 linked_chunk_id,
1364 vec![
1365 Update::NewItemsChunk { previous: None, new: CId::new(42), next: None },
1366 Update::PushItems {
1367 at: Position::new(CId::new(42), 0),
1368 items: vec![
1369 make_test_event(room_id, "one"),
1370 make_test_event(room_id, "two"),
1371 make_test_event(room_id, "three"),
1372 make_test_event(room_id, "four"),
1373 make_test_event(room_id, "five"),
1374 make_test_event(room_id, "six"),
1375 ],
1376 },
1377 Update::RemoveItem { at: Position::new(CId::new(42), 2) },
1378 Update::PushItems {
1390 at: Position::new(CId::new(42), 5),
1391 items: vec![make_test_event(room_id, "seven")],
1392 },
1393 ],
1394 )
1395 .await
1396 .unwrap();
1397
1398 let mut chunks = self.load_all_chunks(linked_chunk_id).await.unwrap();
1399
1400 assert_eq!(chunks.len(), 1);
1401
1402 let c = chunks.remove(0);
1403 assert_eq!(c.identifier, CId::new(42));
1404 assert_eq!(c.previous, None);
1405 assert_eq!(c.next, None);
1406 assert_matches!(c.content, ChunkContent::Items(events) => {
1407 assert_eq!(events.len(), 6);
1408 check_test_event(&events[0], "one");
1409 check_test_event(&events[1], "two");
1410 check_test_event(&events[2], "four");
1411 check_test_event(&events[3], "five");
1412 check_test_event(&events[4], "six");
1413 check_test_event(&events[5], "seven");
1414 });
1415
1416 let metas = self.load_all_chunks_metadata(linked_chunk_id).await.unwrap();
1418 assert_eq!(metas.len(), 1);
1419 assert_eq!(metas[0].num_items, 6);
1420 }
1421
1422 async fn test_linked_chunk_detach_last_items(&self) {
1423 let room_id = *DEFAULT_TEST_ROOM_ID;
1424 let linked_chunk_id = LinkedChunkId::Room(room_id);
1425
1426 self.handle_linked_chunk_updates(
1427 linked_chunk_id,
1428 vec![
1429 Update::NewItemsChunk { previous: None, new: CId::new(42), next: None },
1430 Update::PushItems {
1431 at: Position::new(CId::new(42), 0),
1432 items: vec![
1433 make_test_event(room_id, "hello"),
1434 make_test_event(room_id, "world"),
1435 make_test_event(room_id, "howdy"),
1436 ],
1437 },
1438 Update::DetachLastItems { at: Position::new(CId::new(42), 1) },
1439 ],
1440 )
1441 .await
1442 .unwrap();
1443
1444 let mut chunks = self.load_all_chunks(linked_chunk_id).await.unwrap();
1445
1446 assert_eq!(chunks.len(), 1);
1447
1448 let c = chunks.remove(0);
1449 assert_eq!(c.identifier, CId::new(42));
1450 assert_eq!(c.previous, None);
1451 assert_eq!(c.next, None);
1452 assert_matches!(c.content, ChunkContent::Items(events) => {
1453 assert_eq!(events.len(), 1);
1454 check_test_event(&events[0], "hello");
1455 });
1456 }
1457
1458 async fn test_linked_chunk_start_end_reattach_items(&self) {
1459 let room_id = *DEFAULT_TEST_ROOM_ID;
1460 let linked_chunk_id = LinkedChunkId::Room(room_id);
1461
1462 self.handle_linked_chunk_updates(
1466 linked_chunk_id,
1467 vec![
1468 Update::NewItemsChunk { previous: None, new: CId::new(42), next: None },
1469 Update::PushItems {
1470 at: Position::new(CId::new(42), 0),
1471 items: vec![
1472 make_test_event(room_id, "hello"),
1473 make_test_event(room_id, "world"),
1474 make_test_event(room_id, "howdy"),
1475 ],
1476 },
1477 Update::StartReattachItems,
1478 Update::EndReattachItems,
1479 ],
1480 )
1481 .await
1482 .unwrap();
1483
1484 let mut chunks = self.load_all_chunks(linked_chunk_id).await.unwrap();
1485
1486 assert_eq!(chunks.len(), 1);
1487
1488 let c = chunks.remove(0);
1489 assert_eq!(c.identifier, CId::new(42));
1490 assert_eq!(c.previous, None);
1491 assert_eq!(c.next, None);
1492 assert_matches!(c.content, ChunkContent::Items(events) => {
1493 assert_eq!(events.len(), 3);
1494 check_test_event(&events[0], "hello");
1495 check_test_event(&events[1], "world");
1496 check_test_event(&events[2], "howdy");
1497 });
1498 }
1499
1500 async fn test_linked_chunk_clear(&self) {
1501 let room_id = *DEFAULT_TEST_ROOM_ID;
1502 let linked_chunk_id = LinkedChunkId::Room(room_id);
1503 let event_0 = make_test_event(room_id, "hello");
1504 let event_1 = make_test_event(room_id, "world");
1505 let event_2 = make_test_event(room_id, "howdy");
1506
1507 self.handle_linked_chunk_updates(
1508 linked_chunk_id,
1509 vec![
1510 Update::NewItemsChunk { previous: None, new: CId::new(42), next: None },
1511 Update::NewGapChunk {
1512 previous: Some(CId::new(42)),
1513 new: CId::new(54),
1514 next: None,
1515 gap: Gap { token: "fondue".to_owned() },
1516 },
1517 Update::PushItems {
1518 at: Position::new(CId::new(42), 0),
1519 items: vec![event_0.clone(), event_1, event_2],
1520 },
1521 Update::Clear,
1522 ],
1523 )
1524 .await
1525 .unwrap();
1526
1527 let chunks = self.load_all_chunks(linked_chunk_id).await.unwrap();
1528 assert!(chunks.is_empty());
1529 }
1530
1531 async fn test_linked_chunk_clear_and_reinsert(&self) {
1532 let room_id = *DEFAULT_TEST_ROOM_ID;
1533 let linked_chunk_id = LinkedChunkId::Room(room_id);
1534 let event_0 = make_test_event(room_id, "hello");
1535 let event_1 = make_test_event(room_id, "world");
1536 let event_2 = make_test_event(room_id, "howdy");
1537
1538 self.handle_linked_chunk_updates(
1539 linked_chunk_id,
1540 vec![
1541 Update::NewItemsChunk { previous: None, new: CId::new(42), next: None },
1542 Update::NewGapChunk {
1543 previous: Some(CId::new(42)),
1544 new: CId::new(54),
1545 next: None,
1546 gap: Gap { token: "fondue".to_owned() },
1547 },
1548 Update::PushItems {
1549 at: Position::new(CId::new(42), 0),
1550 items: vec![event_0.clone(), event_1, event_2],
1551 },
1552 Update::Clear,
1553 ],
1554 )
1555 .await
1556 .unwrap();
1557
1558 let chunks = self.load_all_chunks(linked_chunk_id).await.unwrap();
1559 assert!(chunks.is_empty());
1560
1561 self.handle_linked_chunk_updates(
1563 linked_chunk_id,
1564 vec![
1565 Update::NewItemsChunk { previous: None, new: CId::new(42), next: None },
1566 Update::PushItems { at: Position::new(CId::new(42), 0), items: vec![event_0] },
1567 ],
1568 )
1569 .await
1570 .unwrap();
1571 }
1572
1573 async fn test_rebuild_empty_linked_chunk(&self) {
1574 let linked_chunk = lazy_loader::from_all_chunks::<3, _, _>(
1576 self.load_all_chunks(LinkedChunkId::Room(&DEFAULT_TEST_ROOM_ID)).await.unwrap(),
1577 )
1578 .unwrap();
1579 assert!(linked_chunk.is_none());
1580 }
1581
1582 async fn test_linked_chunk_multiple_rooms(&self) {
1583 let room1 = room_id!("!realcheeselovers:raclette.fr");
1584 let linked_chunk_id1 = LinkedChunkId::Room(room1);
1585 let room2 = room_id!("!realcheeselovers:fondue.ch");
1586 let linked_chunk_id2 = LinkedChunkId::Room(room2);
1587
1588 self.handle_linked_chunk_updates(
1592 linked_chunk_id1,
1593 vec![
1594 Update::NewItemsChunk { previous: None, new: CId::new(42), next: None },
1595 Update::PushItems {
1596 at: Position::new(CId::new(42), 0),
1597 items: vec![
1598 make_test_event(room1, "best cheese is raclette"),
1599 make_test_event(room1, "obviously"),
1600 ],
1601 },
1602 ],
1603 )
1604 .await
1605 .unwrap();
1606
1607 self.handle_linked_chunk_updates(
1608 linked_chunk_id2,
1609 vec![
1610 Update::NewItemsChunk { previous: None, new: CId::new(42), next: None },
1611 Update::PushItems {
1612 at: Position::new(CId::new(42), 0),
1613 items: vec![make_test_event(room1, "beaufort is the best")],
1614 },
1615 ],
1616 )
1617 .await
1618 .unwrap();
1619
1620 let mut chunks_room1 = self.load_all_chunks(linked_chunk_id1).await.unwrap();
1622 assert_eq!(chunks_room1.len(), 1);
1623
1624 let c = chunks_room1.remove(0);
1625 assert_matches!(c.content, ChunkContent::Items(events) => {
1626 assert_eq!(events.len(), 2);
1627 check_test_event(&events[0], "best cheese is raclette");
1628 check_test_event(&events[1], "obviously");
1629 });
1630
1631 let mut chunks_room2 = self.load_all_chunks(linked_chunk_id2).await.unwrap();
1633 assert_eq!(chunks_room2.len(), 1);
1634
1635 let c = chunks_room2.remove(0);
1636 assert_matches!(c.content, ChunkContent::Items(events) => {
1637 assert_eq!(events.len(), 1);
1638 check_test_event(&events[0], "beaufort is the best");
1639 });
1640 }
1641
1642 async fn test_load_and_update_thread_info(&self) {
1643 let room_id = room_id!("!r0");
1644 let thread_id = event_id!("$t0");
1645
1646 let ThreadInfo { read_receipts } = self.load_thread_info(room_id, thread_id).await.unwrap();
1650 let ReadReceipts { num_unread, num_notifications, num_mentions, latest_active, pending } =
1651 read_receipts;
1652 assert_eq!(num_unread, 0);
1653 assert_eq!(num_notifications, 0);
1654 assert_eq!(num_mentions, 0);
1655 assert!(latest_active.is_none());
1656 assert!(pending.is_empty());
1657
1658 let mut thread_info = self.load_thread_info(room_id, thread_id).await.unwrap();
1662 let ThreadInfo { read_receipts } = &thread_info;
1663 let ReadReceipts { num_unread, num_notifications, num_mentions, latest_active, pending } =
1664 read_receipts;
1665 assert_eq!(*num_unread, 0);
1666 assert_eq!(*num_notifications, 0);
1667 assert_eq!(*num_mentions, 0);
1668 assert!(latest_active.is_none());
1669 assert!(pending.is_empty());
1670
1671 thread_info.read_receipts.num_unread = 1;
1673 thread_info.read_receipts.num_notifications = 2;
1674 self.update_thread_info(room_id, thread_id, &thread_info).await.unwrap();
1675
1676 let ThreadInfo { read_receipts } = self.load_thread_info(room_id, thread_id).await.unwrap();
1680 let ReadReceipts { num_unread, num_notifications, num_mentions, latest_active, pending } =
1681 read_receipts;
1682 assert_eq!(num_unread, 1);
1683 assert_eq!(num_notifications, 2);
1684 assert_eq!(num_mentions, 0);
1685 assert!(latest_active.is_none());
1686 assert!(pending.is_empty());
1687 }
1688
1689 async fn test_clear_all_events(&self) {
1690 let linked_chunk_ids = [
1691 LinkedChunkId::Room(room_id!("!r0")),
1692 LinkedChunkId::Thread(room_id!("!r1"), event_id!("$r1_thread_root0")),
1693 LinkedChunkId::PinnedEvents(room_id!("!r2")),
1694 ];
1696
1697 for linked_chunk_id in linked_chunk_ids {
1699 let room_id = linked_chunk_id.room_id();
1700
1701 if let LinkedChunkId::Thread(_, thread_id) = &linked_chunk_id {
1704 self.load_thread_info(room_id, thread_id).await.unwrap();
1705 }
1706
1707 self.handle_linked_chunk_updates(
1708 linked_chunk_id,
1709 vec![
1710 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
1712 Update::PushItems {
1714 at: Position::new(CId::new(0), 0),
1715 items: vec![
1716 make_test_event(room_id, "foo"),
1717 make_test_event(room_id, "bar"),
1718 make_test_event(room_id, "baz"),
1719 ],
1720 },
1721 ],
1722 )
1723 .await
1724 .unwrap();
1725
1726 assert!(
1728 lazy_loader::from_all_chunks::<3, _, _>(
1729 self.load_all_chunks(linked_chunk_id).await.unwrap()
1730 )
1731 .unwrap()
1732 .is_some()
1733 );
1734
1735 assert_eq!(self.get_room_events(room_id, None, None).await.unwrap().len(), 3);
1737 }
1738
1739 self.clear_all_events(None).await.unwrap();
1741
1742 for linked_chunk_id in linked_chunk_ids {
1744 let room_id = linked_chunk_id.room_id();
1745
1746 assert!(
1748 lazy_loader::from_all_chunks::<3, _, _>(
1749 self.load_all_chunks(linked_chunk_id).await.unwrap()
1750 )
1751 .unwrap()
1752 .is_none()
1753 );
1754
1755 assert!(self.get_room_events(room_id, None, None).await.unwrap().is_empty());
1757 }
1758 }
1759
1760 async fn test_clear_all_events_for_specific_room(&self) {
1761 let linked_chunk_ids_for_room_0 = [
1762 LinkedChunkId::Room(room_id!("!r0")),
1763 LinkedChunkId::Thread(room_id!("!r0"), event_id!("$r0_thread_root")),
1764 LinkedChunkId::PinnedEvents(room_id!("!r0")),
1765 ];
1766 let linked_chunk_ids_for_room_1 = [
1767 LinkedChunkId::Room(room_id!("!r1")),
1768 LinkedChunkId::Thread(room_id!("!r1"), event_id!("$r1_thread_root")),
1769 LinkedChunkId::PinnedEvents(room_id!("!r1")),
1770 ];
1771 let linked_chunk_ids_for_room_2 = [
1772 LinkedChunkId::Room(room_id!("!r2")),
1773 LinkedChunkId::Thread(room_id!("!r2"), event_id!("$r2_thread_root")),
1774 LinkedChunkId::PinnedEvents(room_id!("!r2")),
1775 ];
1776
1777 for linked_chunk_id in linked_chunk_ids_for_room_0
1779 .iter()
1780 .chain(&linked_chunk_ids_for_room_1)
1781 .chain(&linked_chunk_ids_for_room_2)
1782 {
1783 let room_id = linked_chunk_id.room_id();
1784
1785 if let LinkedChunkId::Thread(_, thread_id) = &linked_chunk_id {
1788 self.load_thread_info(room_id, thread_id).await.unwrap();
1789 }
1790
1791 self.handle_linked_chunk_updates(
1792 *linked_chunk_id,
1793 vec![
1794 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
1796 Update::PushItems {
1798 at: Position::new(CId::new(0), 0),
1799 items: vec![
1800 make_test_event(room_id, "foo"),
1801 make_test_event(room_id, "bar"),
1802 make_test_event(room_id, "baz"),
1803 ],
1804 },
1805 ],
1806 )
1807 .await
1808 .unwrap();
1809
1810 assert!(
1812 lazy_loader::from_all_chunks::<3, _, _>(
1813 self.load_all_chunks(*linked_chunk_id).await.unwrap()
1814 )
1815 .unwrap()
1816 .is_some()
1817 );
1818
1819 assert_eq!(self.get_room_events(room_id, None, None).await.unwrap().len(), 3);
1821 }
1822
1823 self.clear_all_events(Some(linked_chunk_ids_for_room_1[0].room_id())).await.unwrap();
1825
1826 for linked_chunk_id in linked_chunk_ids_for_room_1 {
1828 let room_id = linked_chunk_id.room_id();
1829
1830 assert!(
1832 lazy_loader::from_all_chunks::<3, _, _>(
1833 self.load_all_chunks(linked_chunk_id).await.unwrap()
1834 )
1835 .unwrap()
1836 .is_none()
1837 );
1838
1839 assert!(self.get_room_events(room_id, None, None).await.unwrap().is_empty());
1841 }
1842
1843 for linked_chunk_id in
1845 linked_chunk_ids_for_room_0.iter().chain(&linked_chunk_ids_for_room_2)
1846 {
1847 let room_id = linked_chunk_id.room_id();
1848
1849 assert!(
1851 lazy_loader::from_all_chunks::<3, _, _>(
1852 self.load_all_chunks(*linked_chunk_id).await.unwrap()
1853 )
1854 .unwrap()
1855 .is_some()
1856 );
1857
1858 assert_eq!(self.get_room_events(room_id, None, None).await.unwrap().len(), 3);
1860 }
1861 }
1862
1863 async fn test_filter_duplicated_events(&self) {
1864 let room_id = room_id!("!r0:matrix.org");
1865 let linked_chunk_id = LinkedChunkId::Room(room_id);
1866 let another_room_id = room_id!("!r1:matrix.org");
1867 let another_linked_chunk_id = LinkedChunkId::Room(another_room_id);
1868 let event = |msg: &str| make_test_event(room_id, msg);
1869
1870 let event_comte = event("comté");
1871 let event_brigand = event("brigand du jorat");
1872 let event_raclette = event("raclette");
1873 let event_morbier = event("morbier");
1874 let event_gruyere = event("gruyère");
1875 let event_tome = event("tome");
1876 let event_mont_dor = event("mont d'or");
1877
1878 self.handle_linked_chunk_updates(
1879 linked_chunk_id,
1880 vec![
1881 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
1882 Update::PushItems {
1883 at: Position::new(CId::new(0), 0),
1884 items: vec![event_comte.clone(), event_brigand.clone()],
1885 },
1886 Update::NewGapChunk {
1887 previous: Some(CId::new(0)),
1888 new: CId::new(1),
1889 next: None,
1890 gap: Gap { token: "brillat-savarin".to_owned() },
1891 },
1892 Update::NewItemsChunk { previous: Some(CId::new(1)), new: CId::new(2), next: None },
1893 Update::PushItems {
1894 at: Position::new(CId::new(2), 0),
1895 items: vec![event_morbier.clone(), event_mont_dor.clone()],
1896 },
1897 ],
1898 )
1899 .await
1900 .unwrap();
1901
1902 self.handle_linked_chunk_updates(
1905 another_linked_chunk_id,
1906 vec![
1907 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
1908 Update::PushItems {
1909 at: Position::new(CId::new(0), 0),
1910 items: vec![event_tome.clone()],
1911 },
1912 ],
1913 )
1914 .await
1915 .unwrap();
1916
1917 let duplicated_events = BTreeMap::from_iter(
1918 self.filter_duplicated_events(
1919 linked_chunk_id,
1920 vec![
1921 event_comte.event_id().unwrap().to_owned(),
1922 event_raclette.event_id().unwrap().to_owned(),
1923 event_morbier.event_id().unwrap().to_owned(),
1924 event_gruyere.event_id().unwrap().to_owned(),
1925 event_tome.event_id().unwrap().to_owned(),
1926 event_mont_dor.event_id().unwrap().to_owned(),
1927 ],
1928 )
1929 .await
1930 .unwrap(),
1931 );
1932
1933 assert_eq!(duplicated_events.len(), 3);
1934
1935 assert_eq!(
1936 *duplicated_events.get(event_comte.event_id().unwrap()).unwrap(),
1937 Position::new(CId::new(0), 0)
1938 );
1939 assert_eq!(
1940 *duplicated_events.get(event_morbier.event_id().unwrap()).unwrap(),
1941 Position::new(CId::new(2), 0)
1942 );
1943 assert_eq!(
1944 *duplicated_events.get(event_mont_dor.event_id().unwrap()).unwrap(),
1945 Position::new(CId::new(2), 1)
1946 );
1947 }
1948
1949 async fn test_filter_duplicate_events_no_events(&self) {
1950 let room_id = *DEFAULT_TEST_ROOM_ID;
1951 let linked_chunk_id = LinkedChunkId::Room(room_id);
1952 let duplicates = self.filter_duplicated_events(linked_chunk_id, Vec::new()).await.unwrap();
1953 assert!(duplicates.is_empty());
1954 }
1955
1956 async fn test_find_event(&self) {
1957 let room_id = room_id!("!r0:matrix.org");
1958 let another_room_id = room_id!("!r1:matrix.org");
1959 let another_linked_chunk_id = LinkedChunkId::Room(another_room_id);
1960 let event = |msg: &str| make_test_event(room_id, msg);
1961
1962 let event_comte = event("comté");
1963 let event_gruyere = event("gruyère");
1964
1965 self.handle_linked_chunk_updates(
1967 LinkedChunkId::Room(room_id),
1968 vec![
1969 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
1970 Update::PushItems {
1971 at: Position::new(CId::new(0), 0),
1972 items: vec![event_comte.clone()],
1973 },
1974 ],
1975 )
1976 .await
1977 .unwrap();
1978
1979 self.handle_linked_chunk_updates(
1981 another_linked_chunk_id,
1982 vec![
1983 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
1984 Update::PushItems {
1985 at: Position::new(CId::new(0), 0),
1986 items: vec![event_gruyere.clone()],
1987 },
1988 ],
1989 )
1990 .await
1991 .unwrap();
1992
1993 let event = self
1995 .find_event(room_id, event_comte.event_id().unwrap())
1996 .await
1997 .expect("failed to query for finding an event")
1998 .expect("failed to find an event");
1999
2000 assert_eq!(event.event_id(), event_comte.event_id());
2001
2002 assert!(
2005 self.find_event(room_id, event_gruyere.event_id().unwrap())
2006 .await
2007 .expect("failed to query for finding an event")
2008 .is_none()
2009 );
2010
2011 self.clear_all_events(None).await.expect("failed to clear all rooms chunks");
2013 assert!(
2014 self.find_event(room_id, event_comte.event_id().unwrap())
2015 .await
2016 .expect("failed to query for finding an event")
2017 .is_none()
2018 );
2019 }
2020
2021 async fn test_find_event_when_event_in_room_and_thread(&self) {
2022 let room_id = *DEFAULT_TEST_ROOM_ID;
2023 let thread_root = event_id!("$thread_root");
2024
2025 let room_event_id = event_id!("$room_event");
2027 let room_event = make_test_event_with_event_id(room_id, "room event", Some(room_event_id));
2028
2029 let thread_event_id = event_id!("$thread_event");
2031 let thread_event =
2032 make_test_event_with_event_id(room_id, "thread event", Some(thread_event_id));
2033
2034 let room_and_thread_event_id = event_id!("$room_and_thread");
2037 let room_and_thread_event = make_test_event_with_event_id(
2038 room_id,
2039 "room and thread",
2040 Some(room_and_thread_event_id),
2041 );
2042
2043 let room_linked_chunk_id = LinkedChunkId::Room(room_id);
2044 let thread_linked_chunk_id = LinkedChunkId::Thread(room_id, thread_root);
2045
2046 self.handle_linked_chunk_updates(
2048 room_linked_chunk_id,
2049 vec![
2050 Update::NewItemsChunk { previous: None, new: CId::new(1), next: None },
2051 Update::PushItems {
2052 at: Position::new(CId::new(1), 0),
2053 items: vec![room_event, room_and_thread_event.clone()],
2054 },
2055 ],
2056 )
2057 .await
2058 .unwrap();
2059
2060 self.handle_linked_chunk_updates(
2062 thread_linked_chunk_id,
2063 vec![
2064 Update::NewItemsChunk { previous: None, new: CId::new(1), next: None },
2065 Update::PushItems {
2066 at: Position::new(CId::new(1), 0),
2067 items: vec![thread_event, room_and_thread_event],
2068 },
2069 ],
2070 )
2071 .await
2072 .unwrap();
2073
2074 assert_matches!(self.find_event(room_id, room_event_id).await, Ok(Some(event)) => {
2076 assert_eq!(event.event_id().unwrap(), room_event_id)
2077 });
2078
2079 assert_matches!(self.find_event(room_id, thread_event_id).await, Ok(Some(event)) => {
2081 assert_eq!(event.event_id().unwrap(), thread_event_id)
2082 });
2083
2084 assert_matches!(self.find_event(room_id, room_and_thread_event_id).await, Ok(Some(event)) => {
2086 assert_eq!(event.event_id().unwrap(), room_and_thread_event_id);
2087 });
2088 }
2089
2090 async fn test_find_event_relations(&self) {
2091 let room_id = room_id!("!r0:matrix.org");
2092 let another_room_id = room_id!("!r1:matrix.org");
2093
2094 let f = EventFactory::new().room(room_id).sender(*ALICE);
2095
2096 let eid1 = event_id!("$event1:matrix.org");
2098 let e1 = f.text_msg("comter").event_id(eid1).into_event();
2099
2100 let edit_eid1 = event_id!("$edit_event1:matrix.org");
2101 let edit_e1 = f
2102 .text_msg("* comté")
2103 .event_id(edit_eid1)
2104 .edit(eid1, RoomMessageEventContentWithoutRelation::text_plain("comté"))
2105 .into_event();
2106
2107 let reaction_eid1 = event_id!("$reaction_event1:matrix.org");
2108 let reaction_e1 = f.reaction(eid1, "👍").event_id(reaction_eid1).into_event();
2109
2110 let eid2 = event_id!("$event2:matrix.org");
2111 let e2 = f.text_msg("galette saucisse").event_id(eid2).into_event();
2112
2113 let f = f.room(another_room_id);
2115
2116 let eid3 = event_id!("$event3:matrix.org");
2117 let e3 = f.text_msg("gruyère").event_id(eid3).into_event();
2118
2119 let reaction_eid3 = event_id!("$reaction_event3:matrix.org");
2120 let reaction_e3 = f.reaction(eid3, "👍").event_id(reaction_eid3).into_event();
2121
2122 self.save_event(room_id, e1).await.unwrap();
2124 self.save_event(room_id, edit_e1).await.unwrap();
2125 self.save_event(room_id, reaction_e1.clone()).await.unwrap();
2126 self.save_event(room_id, e2).await.unwrap();
2127 self.save_event(another_room_id, e3).await.unwrap();
2128 self.save_event(another_room_id, reaction_e3).await.unwrap();
2129
2130 let relations = self.find_event_relations(room_id, eid1, None).await.unwrap();
2132 assert_eq!(relations.len(), 2);
2133 assert!(
2135 relations.iter().any(|(ev, pos)| ev.event_id() == Some(edit_eid1) && pos.is_none())
2136 );
2137 assert!(
2138 relations.iter().any(|(ev, pos)| ev.event_id() == Some(reaction_eid1) && pos.is_none())
2139 );
2140
2141 let relations = self
2143 .find_event_relations(room_id, eid1, Some(&[RelationType::Replacement]))
2144 .await
2145 .unwrap();
2146 assert_eq!(relations.len(), 1);
2147 assert_eq!(relations[0].0.event_id(), Some(edit_eid1));
2148
2149 let relations = self
2150 .find_event_relations(
2151 room_id,
2152 eid1,
2153 Some(&[RelationType::Replacement, RelationType::Annotation]),
2154 )
2155 .await
2156 .unwrap();
2157 assert_eq!(relations.len(), 2);
2158 assert!(relations.iter().any(|r| r.0.event_id() == Some(edit_eid1)));
2159 assert!(relations.iter().any(|r| r.0.event_id() == Some(reaction_eid1)));
2160
2161 let relations = self
2163 .find_event_relations(another_room_id, eid1, Some(&[RelationType::Replacement]))
2164 .await
2165 .unwrap();
2166 assert!(relations.is_empty());
2167
2168 self.handle_linked_chunk_updates(
2173 LinkedChunkId::Room(room_id),
2174 vec![
2175 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
2176 Update::PushItems { at: Position::new(CId::new(0), 0), items: vec![reaction_e1] },
2177 ],
2178 )
2179 .await
2180 .unwrap();
2181
2182 let relations = self.find_event_relations(room_id, eid1, None).await.unwrap();
2185
2186 assert!(relations.iter().any(|(ev, pos)| {
2188 ev.event_id() == Some(reaction_eid1) && *pos == Some(Position::new(CId::new(0), 0))
2189 }));
2190
2191 assert!(
2193 relations.iter().any(|(ev, pos)| ev.event_id() == Some(edit_eid1) && pos.is_none())
2194 );
2195 }
2196
2197 async fn test_find_event_relations_when_event_in_room_and_thread(&self) {
2198 let room_id = *DEFAULT_TEST_ROOM_ID;
2199 let thread_root = event_id!("$thread_root");
2200
2201 let event_id = event_id!("$event");
2204 let event = make_test_event_with_event_id(room_id, "event", Some(event_id));
2205
2206 let extra_thread_event_id = event_id!("$extra_thread_event");
2209 let extra_thread_event = make_test_event_with_event_id(
2210 room_id,
2211 "extra thread event",
2212 Some(extra_thread_event_id),
2213 );
2214
2215 let room_reaction_id = event_id!("$room_reaction");
2217 let room_reaction = EventFactory::new()
2218 .room(room_id)
2219 .sender(*ALICE)
2220 .reaction(event_id, "room")
2221 .event_id(room_reaction_id)
2222 .into_event();
2223
2224 let thread_reaction_id = event_id!("$thread_reaction");
2226 let thread_reaction = EventFactory::new()
2227 .room(room_id)
2228 .sender(*ALICE)
2229 .reaction(event_id, "thread")
2230 .event_id(thread_reaction_id)
2231 .into_event();
2232
2233 let room_and_thread_reaction_id = event_id!("$room_and_thread_reaction");
2236 let room_and_thread_reaction = EventFactory::new()
2237 .room(room_id)
2238 .sender(*ALICE)
2239 .reaction(event_id, "room and thread")
2240 .event_id(room_and_thread_reaction_id)
2241 .into_event();
2242
2243 let room_linked_chunk_id = LinkedChunkId::Room(room_id);
2244 let thread_linked_chunk_id = LinkedChunkId::Thread(room_id, thread_root);
2245
2246 self.handle_linked_chunk_updates(
2248 room_linked_chunk_id,
2249 vec![
2250 Update::NewItemsChunk { previous: None, new: CId::new(1), next: None },
2251 Update::PushItems {
2252 at: Position::new(CId::new(1), 0),
2253 items: vec![event.clone(), room_reaction, room_and_thread_reaction.clone()],
2254 },
2255 ],
2256 )
2257 .await
2258 .unwrap();
2259
2260 self.handle_linked_chunk_updates(
2262 thread_linked_chunk_id,
2263 vec![
2264 Update::NewItemsChunk { previous: None, new: CId::new(1), next: None },
2265 Update::PushItems {
2266 at: Position::new(CId::new(1), 0),
2267 items: vec![
2268 event.clone(),
2269 extra_thread_event,
2270 thread_reaction,
2271 room_and_thread_reaction,
2272 ],
2273 },
2274 ],
2275 )
2276 .await
2277 .unwrap();
2278
2279 assert_matches!(self.find_event_relations(room_id, event_id, None).await, Ok(relations) => {
2281 assert_eq!(relations.len(), 3);
2282 let room_relation = relations
2285 .iter()
2286 .find(|relation| relation.0.event_id().unwrap() == room_reaction_id)
2287 .unwrap();
2288 assert_matches!(room_relation, (_, Some(position)) => {
2289 assert_eq!(*position, Position::new(CId::new(1), 1));
2290 });
2291
2292 let thread_relation = relations
2296 .iter()
2297 .find(|relation| relation.0.event_id().unwrap() == thread_reaction_id)
2298 .unwrap();
2299 assert_matches!(thread_relation, (_, None));
2300
2301 let room_and_thread_relation = relations
2305 .iter()
2306 .find(|relation| relation.0.event_id().unwrap() == room_and_thread_reaction_id)
2307 .unwrap();
2308 assert_matches!(room_and_thread_relation, (_, Some(position)) => {
2309 assert_eq!(*position, Position::new(CId::new(1), 2));
2310 });
2311 });
2312 }
2313
2314 async fn test_get_room_events(&self) {
2315 let room_id = room_id!("!r0:matrix.org");
2316 let another_room_id = room_id!("!r1:matrix.org");
2317 let linked_chunk_id = LinkedChunkId::Room(room_id);
2318 let another_linked_chunk_id = LinkedChunkId::Room(another_room_id);
2319 let event = |msg: &str| make_test_event(room_id, msg);
2320
2321 let event_comte = event("comté");
2322 let event_gruyere = event("gruyère");
2323 let event_stilton = event("stilton");
2324
2325 self.handle_linked_chunk_updates(
2327 linked_chunk_id,
2328 vec![
2329 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
2330 Update::PushItems {
2331 at: Position::new(CId::new(0), 0),
2332 items: vec![event_comte.clone(), event_gruyere.clone()],
2333 },
2334 ],
2335 )
2336 .await
2337 .unwrap();
2338
2339 self.handle_linked_chunk_updates(
2341 another_linked_chunk_id,
2342 vec![
2343 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
2344 Update::PushItems {
2345 at: Position::new(CId::new(0), 0),
2346 items: vec![event_stilton.clone()],
2347 },
2348 ],
2349 )
2350 .await
2351 .unwrap();
2352
2353 let events = self
2355 .get_room_events(room_id, None, None)
2356 .await
2357 .expect("failed to query for room events");
2358
2359 assert_eq!(events.len(), 2);
2360
2361 let got_ids: Vec<_> =
2362 events.into_iter().map(|ev| ev.event_id().map(ToOwned::to_owned)).collect();
2363 let expected_ids = vec![
2364 event_comte.event_id().map(ToOwned::to_owned),
2365 event_gruyere.event_id().map(ToOwned::to_owned),
2366 ];
2367
2368 for expected in expected_ids {
2369 assert!(
2370 got_ids.contains(&expected),
2371 "Expected event {expected:?} not in got events: {got_ids:?}."
2372 );
2373 }
2374 }
2375
2376 async fn test_get_room_events_filtered(&self) {
2377 macro_rules! assert_expected_events {
2378 ($events:expr, [$($item:expr),* $(,)?]) => {{
2379 let got_ids: BTreeSet<_> = $events.into_iter().map(|ev| ev.event_id().map(ToOwned::to_owned)).flatten().collect();
2380 let expected_ids = BTreeSet::from([$($item.event_id().unwrap().to_owned()),*]);
2381
2382 assert_eq!(got_ids, expected_ids);
2383 }};
2384 }
2385
2386 let room_id = room_id!("!r0:matrix.org");
2387 let linked_chunk_id = LinkedChunkId::Room(room_id);
2388 let another_room_id = room_id!("!r1:matrix.org");
2389 let another_linked_chunk_id = LinkedChunkId::Room(another_room_id);
2390
2391 let event = |session_id: &str| make_encrypted_test_event(room_id, session_id);
2392
2393 let first_event = event("session_1");
2394 let second_event = event("session_2");
2395 let third_event = event("session_3");
2396 let fourth_event = make_test_event(room_id, "It's a secret to everybody");
2397
2398 self.handle_linked_chunk_updates(
2400 linked_chunk_id,
2401 vec![
2402 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
2403 Update::PushItems {
2404 at: Position::new(CId::new(0), 0),
2405 items: vec![first_event.clone(), second_event.clone(), fourth_event.clone()],
2406 },
2407 ],
2408 )
2409 .await
2410 .unwrap();
2411
2412 self.handle_linked_chunk_updates(
2414 another_linked_chunk_id,
2415 vec![
2416 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
2417 Update::PushItems {
2418 at: Position::new(CId::new(0), 0),
2419 items: vec![third_event.clone()],
2420 },
2421 ],
2422 )
2423 .await
2424 .unwrap();
2425
2426 let events = self
2428 .get_room_events(room_id, Some("m.room.encrypted"), None)
2429 .await
2430 .expect("failed to query for room events");
2431
2432 assert_eq!(events.len(), 2);
2433 assert_expected_events!(events, [first_event, second_event]);
2434
2435 let events = self
2438 .get_room_events(room_id, Some("m.room.encrypted"), Some("session_1"))
2439 .await
2440 .expect("failed to query for room events");
2441
2442 assert_eq!(events.len(), 1);
2443 assert_expected_events!(events, [first_event]);
2444 }
2445
2446 async fn test_get_room_events_with_event_in_room_and_thread(&self) {
2447 let room_id = *DEFAULT_TEST_ROOM_ID;
2448 let thread_root = event_id!("$thread_root");
2449
2450 let room_event_id = event_id!("$room_event");
2452 let room_event = make_test_event_with_event_id(room_id, "room event", Some(room_event_id));
2453
2454 let thread_event_id = event_id!("$thread_event");
2458 let thread_event =
2459 make_test_event_with_event_id(room_id, "thread event", Some(thread_event_id));
2460
2461 let room_and_thread_event_id = event_id!("$room_and_thread");
2464 let room_and_thread_event = make_test_event_with_event_id(
2465 room_id,
2466 "room and thread",
2467 Some(room_and_thread_event_id),
2468 );
2469
2470 let room_linked_chunk_id = LinkedChunkId::Room(room_id);
2471 let thread_linked_chunk_id = LinkedChunkId::Thread(room_id, thread_root);
2472
2473 self.handle_linked_chunk_updates(
2475 room_linked_chunk_id,
2476 vec![
2477 Update::NewItemsChunk { previous: None, new: CId::new(1), next: None },
2478 Update::PushItems {
2479 at: Position::new(CId::new(1), 0),
2480 items: vec![room_event, room_and_thread_event.clone()],
2481 },
2482 ],
2483 )
2484 .await
2485 .unwrap();
2486
2487 self.handle_linked_chunk_updates(
2489 thread_linked_chunk_id,
2490 vec![
2491 Update::NewItemsChunk { previous: None, new: CId::new(1), next: None },
2492 Update::PushItems {
2493 at: Position::new(CId::new(1), 0),
2494 items: vec![thread_event, room_and_thread_event],
2495 },
2496 ],
2497 )
2498 .await
2499 .unwrap();
2500
2501 let expected_event_ids =
2504 BTreeSet::from([room_event_id, thread_event_id, room_and_thread_event_id]);
2505 assert_matches!(self.get_room_events(room_id, None, None).await, Ok(events) => {
2506 assert_eq!(events.len(), 3);
2507 assert!(events.iter().all(|event| {
2508 expected_event_ids.contains(event.event_id().unwrap())
2509 }));
2510 });
2511 }
2512
2513 async fn test_save_event(&self) {
2514 let room_id = room_id!("!r0:matrix.org");
2515 let another_room_id = room_id!("!r1:matrix.org");
2516
2517 let event = |msg: &str| make_test_event(room_id, msg);
2518 let event_comte = event("comté");
2519 let event_gruyere = event("gruyère");
2520
2521 self.save_event(room_id, event_comte.clone()).await.unwrap();
2523
2524 self.save_event(another_room_id, event_gruyere.clone()).await.unwrap();
2526
2527 let event = self
2529 .find_event(room_id, event_comte.event_id().unwrap())
2530 .await
2531 .expect("failed to query for finding an event")
2532 .expect("failed to find an event");
2533 assert_eq!(event.event_id(), event_comte.event_id());
2534
2535 let event = self
2536 .find_event(another_room_id, event_gruyere.event_id().unwrap())
2537 .await
2538 .expect("failed to query for finding an event")
2539 .expect("failed to find an event");
2540 assert_eq!(event.event_id(), event_gruyere.event_id());
2541
2542 assert!(
2544 self.find_event(another_room_id, event_comte.event_id().unwrap())
2545 .await
2546 .expect("failed to query for finding an event")
2547 .is_none()
2548 );
2549 assert!(
2550 self.find_event(room_id, event_gruyere.event_id().unwrap())
2551 .await
2552 .expect("failed to query for finding an event")
2553 .is_none()
2554 );
2555 }
2556
2557 async fn test_save_event_updates_event_in_room_and_thread(&self) {
2558 let room_id = *DEFAULT_TEST_ROOM_ID;
2559 let thread_root = event_id!("$thread_root");
2560
2561 let event_id = event_id!("$event");
2564 let event = make_test_event_with_event_id(room_id, "event", Some(event_id));
2565
2566 let room_linked_chunk_id = LinkedChunkId::Room(room_id);
2567 let thread_linked_chunk_id = LinkedChunkId::Thread(room_id, thread_root);
2568
2569 self.handle_linked_chunk_updates(
2571 room_linked_chunk_id,
2572 vec![
2573 Update::NewItemsChunk { previous: None, new: CId::new(1), next: None },
2574 Update::PushItems { at: Position::new(CId::new(1), 0), items: vec![event.clone()] },
2575 ],
2576 )
2577 .await
2578 .unwrap();
2579
2580 self.handle_linked_chunk_updates(
2582 thread_linked_chunk_id,
2583 vec![
2584 Update::NewItemsChunk { previous: None, new: CId::new(1), next: None },
2585 Update::PushItems { at: Position::new(CId::new(1), 0), items: vec![event.clone()] },
2586 ],
2587 )
2588 .await
2589 .unwrap();
2590
2591 let updated_content = "updated content";
2594 let updated = make_test_event_with_event_id(room_id, updated_content, Some(event_id));
2595 self.save_event(room_id, updated).await.unwrap();
2596
2597 let room_chunks = self.load_all_chunks(room_linked_chunk_id).await.unwrap();
2599 let thread_chunks = self.load_all_chunks(thread_linked_chunk_id).await.unwrap();
2600
2601 assert_eq!(room_chunks.len(), 1);
2602 assert_eq!(thread_chunks.len(), 1);
2603
2604 assert_matches!(&room_chunks[0].content, ChunkContent::Items(events) => {
2606 assert_eq!(events.len(), 1);
2607 assert_eq!(events[0].event_id(), Some(event_id));
2608 check_test_event(&events[0], updated_content);
2609 });
2610 assert_matches!(&thread_chunks[0].content, ChunkContent::Items(events) => {
2611 assert_eq!(events.len(), 1);
2612 assert_eq!(events[0].event_id(), Some(event_id));
2613 check_test_event(&events[0], updated_content);
2614 });
2615 }
2616
2617 async fn test_thread_vs_room_linked_chunk(&self) {
2618 let room_id = room_id!("!r0:matrix.org");
2619
2620 let event = |msg: &str| make_test_event(room_id, msg);
2621
2622 let thread1_ev = event("comté");
2623 let thread2_ev = event("gruyère");
2624 let thread2_ev2 = event("beaufort");
2625 let room_ev = event("brillat savarin triple crème");
2626
2627 let thread_root1 = event("thread1");
2628 let thread_root2 = event("thread2");
2629
2630 self.handle_linked_chunk_updates(
2632 LinkedChunkId::Thread(room_id, thread_root1.event_id().unwrap()),
2633 vec![
2634 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
2635 Update::PushItems {
2636 at: Position::new(CId::new(0), 0),
2637 items: vec![thread1_ev.clone()],
2638 },
2639 ],
2640 )
2641 .await
2642 .unwrap();
2643
2644 self.handle_linked_chunk_updates(
2646 LinkedChunkId::Thread(room_id, thread_root2.event_id().unwrap()),
2647 vec![
2648 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
2649 Update::PushItems {
2650 at: Position::new(CId::new(0), 0),
2651 items: vec![thread2_ev.clone(), thread2_ev2.clone()],
2652 },
2653 ],
2654 )
2655 .await
2656 .unwrap();
2657
2658 self.handle_linked_chunk_updates(
2660 LinkedChunkId::Room(room_id),
2661 vec![
2662 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
2663 Update::PushItems {
2664 at: Position::new(CId::new(0), 0),
2665 items: vec![room_ev.clone()],
2666 },
2667 ],
2668 )
2669 .await
2670 .unwrap();
2671
2672 self.find_event(room_id, thread2_ev.event_id().unwrap())
2674 .await
2675 .expect("failed to query for finding an event")
2676 .expect("failed to find thread1_ev");
2677
2678 self.find_event(room_id, thread2_ev.event_id().unwrap())
2679 .await
2680 .expect("failed to query for finding an event")
2681 .expect("failed to find thread2_ev");
2682
2683 self.find_event(room_id, thread2_ev2.event_id().unwrap())
2684 .await
2685 .expect("failed to query for finding an event")
2686 .expect("failed to find thread2_ev2");
2687
2688 self.find_event(room_id, room_ev.event_id().unwrap())
2689 .await
2690 .expect("failed to query for finding an event")
2691 .expect("failed to find room_ev");
2692
2693 let dups = self
2695 .filter_duplicated_events(
2696 LinkedChunkId::Thread(room_id, thread_root1.event_id().unwrap()),
2697 vec![
2698 thread1_ev.event_id().unwrap().to_owned(),
2699 room_ev.event_id().unwrap().to_owned(),
2700 ],
2701 )
2702 .await
2703 .unwrap();
2704 assert_eq!(dups.len(), 1);
2705 assert_eq!(dups[0].0, thread1_ev.event_id().unwrap());
2706
2707 let all_chunks = self
2709 .load_all_chunks(LinkedChunkId::Thread(room_id, thread_root2.event_id().unwrap()))
2710 .await
2711 .unwrap();
2712 assert_eq!(all_chunks.len(), 1);
2713 assert_eq!(all_chunks[0].identifier, CId::new(0));
2714 assert_let!(ChunkContent::Items(observed_items) = all_chunks[0].content.clone());
2715 assert_eq!(observed_items.len(), 2);
2716 assert_eq!(observed_items[0].event_id(), thread2_ev.event_id());
2717 assert_eq!(observed_items[1].event_id(), thread2_ev2.event_id());
2718
2719 let metas = self
2722 .load_all_chunks_metadata(LinkedChunkId::Thread(
2723 room_id,
2724 thread_root2.event_id().unwrap(),
2725 ))
2726 .await
2727 .unwrap();
2728 assert_eq!(metas.len(), 1);
2729 assert_eq!(metas[0].identifier, CId::new(0));
2730 assert_eq!(metas[0].num_items, 2);
2731
2732 let (last_chunk, _chunk_identifier_generator) = self
2734 .load_last_chunk(LinkedChunkId::Thread(room_id, thread_root1.event_id().unwrap()))
2735 .await
2736 .unwrap();
2737 let last_chunk = last_chunk.unwrap();
2738 assert_eq!(last_chunk.identifier, CId::new(0));
2739 assert_let!(ChunkContent::Items(observed_items) = last_chunk.content);
2740 assert_eq!(observed_items.len(), 1);
2741 assert_eq!(observed_items[0].event_id(), thread1_ev.event_id());
2742 }
2743}
2744
2745#[allow(unused_macros, unused_extern_crates)]
2775#[macro_export]
2776macro_rules! event_cache_store_integration_tests {
2777 () => {
2778 mod event_cache_store_integration_tests {
2779 use matrix_sdk_test::async_test;
2780 use $crate::event_cache::store::{
2781 EventCacheStoreIntegrationTests, IntoEventCacheStore,
2782 };
2783
2784 use super::get_event_cache_store;
2785
2786 #[async_test]
2787 async fn test_handle_updates_and_rebuild_linked_chunk() {
2788 let event_cache_store =
2789 get_event_cache_store().await.unwrap().into_event_cache_store();
2790 event_cache_store.test_handle_updates_and_rebuild_linked_chunk().await;
2791 }
2792
2793 #[async_test]
2794 async fn test_linked_chunk_exists_before_referenced() {
2795 let event_cache_store =
2796 get_event_cache_store().await.unwrap().into_event_cache_store();
2797 event_cache_store.test_linked_chunk_exists_before_referenced().await;
2798 }
2799
2800 #[async_test]
2801 async fn test_linked_chunk_allow_same_event_in_room_and_thread() {
2802 let event_cache_store =
2803 get_event_cache_store().await.unwrap().into_event_cache_store();
2804 event_cache_store.test_linked_chunk_allows_same_event_in_room_and_thread().await;
2805 }
2806
2807 #[async_test]
2808 async fn test_load_last_chunk() {
2809 let event_cache_store =
2810 get_event_cache_store().await.unwrap().into_event_cache_store();
2811 event_cache_store.test_load_last_chunk().await;
2812 }
2813
2814 #[async_test]
2815 async fn test_load_last_chunk_with_a_cycle() {
2816 let event_cache_store =
2817 get_event_cache_store().await.unwrap().into_event_cache_store();
2818 event_cache_store.test_load_last_chunk_with_a_cycle().await;
2819 }
2820
2821 #[async_test]
2822 async fn test_load_previous_chunk() {
2823 let event_cache_store =
2824 get_event_cache_store().await.unwrap().into_event_cache_store();
2825 event_cache_store.test_load_previous_chunk().await;
2826 }
2827
2828 #[async_test]
2829 async fn test_linked_chunk_incremental_loading() {
2830 let event_cache_store =
2831 get_event_cache_store().await.unwrap().into_event_cache_store();
2832 event_cache_store.test_linked_chunk_incremental_loading().await;
2833 }
2834
2835 #[async_test]
2836 async fn test_linked_chunk_remove_chunk() {
2837 let event_cache_store =
2838 get_event_cache_store().await.unwrap().into_event_cache_store();
2839 event_cache_store.test_linked_chunk_remove_chunk().await;
2840 }
2841
2842 #[async_test]
2843 async fn test_linked_chunk_push_items() {
2844 let event_cache_store =
2845 get_event_cache_store().await.unwrap().into_event_cache_store();
2846 event_cache_store.test_linked_chunk_push_items().await;
2847 }
2848
2849 #[async_test]
2850 async fn test_linked_chunk_replace_item() {
2851 let event_cache_store =
2852 get_event_cache_store().await.unwrap().into_event_cache_store();
2853 event_cache_store.test_linked_chunk_replace_item().await;
2854 }
2855
2856 #[async_test]
2857 async fn test_linked_chunk_filter_incomplete_events() {
2858 let event_cache_store =
2859 get_event_cache_store().await.unwrap().into_event_cache_store();
2860 event_cache_store.test_linked_chunk_filter_incomplete_events().await;
2861 }
2862
2863 #[async_test]
2864 async fn test_linked_chunk_remove_item() {
2865 let event_cache_store =
2866 get_event_cache_store().await.unwrap().into_event_cache_store();
2867 event_cache_store.test_linked_chunk_remove_item().await;
2868 }
2869
2870 #[async_test]
2871 async fn test_linked_chunk_detach_last_items() {
2872 let event_cache_store =
2873 get_event_cache_store().await.unwrap().into_event_cache_store();
2874 event_cache_store.test_linked_chunk_detach_last_items().await;
2875 }
2876
2877 #[async_test]
2878 async fn test_linked_chunk_start_end_reattach_items() {
2879 let event_cache_store =
2880 get_event_cache_store().await.unwrap().into_event_cache_store();
2881 event_cache_store.test_linked_chunk_start_end_reattach_items().await;
2882 }
2883
2884 #[async_test]
2885 async fn test_linked_chunk_clear() {
2886 let event_cache_store =
2887 get_event_cache_store().await.unwrap().into_event_cache_store();
2888 event_cache_store.test_linked_chunk_clear().await;
2889 }
2890
2891 #[async_test]
2892 async fn test_linked_chunk_clear_and_reinsert() {
2893 let event_cache_store =
2894 get_event_cache_store().await.unwrap().into_event_cache_store();
2895 event_cache_store.test_linked_chunk_clear_and_reinsert().await;
2896 }
2897
2898 #[async_test]
2899 async fn test_rebuild_empty_linked_chunk() {
2900 let event_cache_store =
2901 get_event_cache_store().await.unwrap().into_event_cache_store();
2902 event_cache_store.test_rebuild_empty_linked_chunk().await;
2903 }
2904
2905 #[async_test]
2906 async fn test_linked_chunk_multiple_rooms() {
2907 let event_cache_store =
2908 get_event_cache_store().await.unwrap().into_event_cache_store();
2909 event_cache_store.test_linked_chunk_multiple_rooms().await;
2910 }
2911
2912 #[async_test]
2913 async fn test_load_all_chunks_metadata() {
2914 let event_cache_store =
2915 get_event_cache_store().await.unwrap().into_event_cache_store();
2916 event_cache_store.test_load_all_chunks_metadata().await;
2917 }
2918
2919 #[async_test]
2920 async fn test_load_and_update_thread_info() {
2921 let event_cache_store =
2922 get_event_cache_store().await.unwrap().into_event_cache_store();
2923 event_cache_store.test_load_and_update_thread_info().await;
2924 }
2925
2926 #[async_test]
2927 async fn test_clear_all_events() {
2928 let event_cache_store =
2929 get_event_cache_store().await.unwrap().into_event_cache_store();
2930 event_cache_store.test_clear_all_events().await;
2931 }
2932
2933 #[async_test]
2934 async fn test_clear_all_events_for_specific_room() {
2935 let event_cache_store =
2936 get_event_cache_store().await.unwrap().into_event_cache_store();
2937 event_cache_store.test_clear_all_events_for_specific_room().await;
2938 }
2939
2940 #[async_test]
2941 async fn test_filter_duplicated_events() {
2942 let event_cache_store =
2943 get_event_cache_store().await.unwrap().into_event_cache_store();
2944 event_cache_store.test_filter_duplicated_events().await;
2945 }
2946
2947 #[async_test]
2948 async fn test_filter_duplicate_events_no_events() {
2949 let event_cache_store =
2950 get_event_cache_store().await.unwrap().into_event_cache_store();
2951 event_cache_store.test_filter_duplicate_events_no_events().await;
2952 }
2953
2954 #[async_test]
2955 async fn test_find_event() {
2956 let event_cache_store =
2957 get_event_cache_store().await.unwrap().into_event_cache_store();
2958 event_cache_store.test_find_event().await;
2959 }
2960
2961 #[async_test]
2962 async fn test_find_event_when_event_in_room_and_thread() {
2963 let event_cache_store =
2964 get_event_cache_store().await.unwrap().into_event_cache_store();
2965 event_cache_store.test_find_event_when_event_in_room_and_thread().await;
2966 }
2967
2968 #[async_test]
2969 async fn test_find_event_relations() {
2970 let event_cache_store =
2971 get_event_cache_store().await.unwrap().into_event_cache_store();
2972 event_cache_store.test_find_event_relations().await;
2973 }
2974
2975 #[async_test]
2976 async fn test_find_event_relations_when_event_in_room_and_thread() {
2977 let event_cache_store =
2978 get_event_cache_store().await.unwrap().into_event_cache_store();
2979 event_cache_store.test_find_event_relations_when_event_in_room_and_thread().await;
2980 }
2981
2982 #[async_test]
2983 async fn test_get_room_events() {
2984 let event_cache_store =
2985 get_event_cache_store().await.unwrap().into_event_cache_store();
2986 event_cache_store.test_get_room_events().await;
2987 }
2988
2989 #[async_test]
2990 async fn test_get_room_events_filtered() {
2991 let event_cache_store =
2992 get_event_cache_store().await.unwrap().into_event_cache_store();
2993 event_cache_store.test_get_room_events_filtered().await;
2994 }
2995
2996 #[async_test]
2997 async fn test_get_room_events_with_event_in_room_and_thread() {
2998 let event_cache_store =
2999 get_event_cache_store().await.unwrap().into_event_cache_store();
3000 event_cache_store.test_get_room_events_with_event_in_room_and_thread().await;
3001 }
3002
3003 #[async_test]
3004 async fn test_save_event() {
3005 let event_cache_store =
3006 get_event_cache_store().await.unwrap().into_event_cache_store();
3007 event_cache_store.test_save_event().await;
3008 }
3009
3010 #[async_test]
3011 async fn test_save_event_updates_event_in_room_and_thread() {
3012 let event_cache_store =
3013 get_event_cache_store().await.unwrap().into_event_cache_store();
3014 event_cache_store.test_save_event_updates_event_in_room_and_thread().await;
3015 }
3016
3017 #[async_test]
3018 async fn test_thread_vs_room_linked_chunk() {
3019 let event_cache_store =
3020 get_event_cache_store().await.unwrap().into_event_cache_store();
3021 event_cache_store.test_thread_vs_room_linked_chunk().await;
3022 }
3023 }
3024 };
3025}
3026
3027#[allow(unused_macros)]
3030#[macro_export]
3031macro_rules! event_cache_store_integration_tests_time {
3032 () => {
3033 mod event_cache_store_integration_tests_time {
3034 use std::time::Duration;
3035
3036 #[cfg(all(target_family = "wasm", target_os = "unknown"))]
3037 use gloo_timers::future::sleep;
3038 use matrix_sdk_test::async_test;
3039 #[cfg(not(all(target_family = "wasm", target_os = "unknown")))]
3040 use tokio::time::sleep;
3041 use $crate::event_cache::store::IntoEventCacheStore;
3042
3043 use super::get_event_cache_store;
3044
3045 #[async_test]
3046 async fn test_lease_locks() {
3047 let store = get_event_cache_store().await.unwrap().into_event_cache_store();
3048
3049 let acquired0 = store.try_take_leased_lock(0, "key", "alice").await.unwrap();
3050 assert_eq!(acquired0, Some(1)); let acquired2 = store.try_take_leased_lock(300, "key", "alice").await.unwrap();
3054 assert_eq!(acquired2, Some(1)); let acquired3 = store.try_take_leased_lock(300, "key", "alice").await.unwrap();
3059 assert_eq!(acquired3, Some(1)); let acquired4 = store.try_take_leased_lock(300, "key", "bob").await.unwrap();
3064 assert!(acquired4.is_none()); let acquired5 = store.try_take_leased_lock(300, "key", "bob").await.unwrap();
3068 assert!(acquired5.is_none()); sleep(Duration::from_millis(50)).await;
3072
3073 let acquired55 = store.try_take_leased_lock(300, "key", "bob").await.unwrap();
3075 assert!(acquired55.is_none()); sleep(Duration::from_millis(250)).await;
3079
3080 let acquired6 = store.try_take_leased_lock(0, "key", "bob").await.unwrap();
3082 assert_eq!(acquired6, Some(2)); sleep(Duration::from_millis(1)).await;
3085
3086 let acquired7 = store.try_take_leased_lock(0, "key", "alice").await.unwrap();
3088 assert_eq!(acquired7, Some(3)); sleep(Duration::from_millis(1)).await;
3091
3092 let acquired8 = store.try_take_leased_lock(300, "key", "bob").await.unwrap();
3094 assert_eq!(acquired8, Some(4)); let acquired9 = store.try_take_leased_lock(300, "key", "alice").await.unwrap();
3098 assert!(acquired9.is_none()); let acquired10 = store.try_take_leased_lock(300, "key", "bob").await.unwrap();
3102 assert_eq!(acquired10, Some(4)); }
3104 }
3105 };
3106}