1use std::sync::Arc;
18
19use assert_matches::assert_matches;
20use matrix_sdk_common::{
21 deserialized_responses::{
22 AlgorithmInfo, DecryptedRoomEvent, EncryptionInfo, TimelineEvent, TimelineEventKind,
23 VerificationState,
24 },
25 linked_chunk::{
26 lazy_loader, ChunkContent, ChunkIdentifier as CId, LinkedChunkId, Position, Update,
27 },
28};
29use matrix_sdk_test::{event_factory::EventFactory, ALICE, DEFAULT_TEST_ROOM_ID};
30use ruma::{
31 api::client::media::get_content_thumbnail::v3::Method,
32 event_id,
33 events::{
34 relation::RelationType,
35 room::{message::RoomMessageEventContentWithoutRelation, MediaSource},
36 },
37 mxc_uri,
38 push::Action,
39 room_id, uint, EventId, RoomId,
40};
41
42use super::{media::IgnoreMediaRetentionPolicy, DynEventCacheStore};
43use crate::{
44 event_cache::{store::DEFAULT_CHUNK_CAPACITY, Gap},
45 media::{MediaFormat, MediaRequestParameters, MediaThumbnailSettings},
46};
47
48pub fn make_test_event(room_id: &RoomId, content: &str) -> TimelineEvent {
53 make_test_event_with_event_id(room_id, content, None)
54}
55
56pub fn make_test_event_with_event_id(
58 room_id: &RoomId,
59 content: &str,
60 event_id: Option<&EventId>,
61) -> TimelineEvent {
62 let encryption_info = Arc::new(EncryptionInfo {
63 sender: (*ALICE).into(),
64 sender_device: None,
65 algorithm_info: AlgorithmInfo::MegolmV1AesSha2 {
66 curve25519_key: "1337".to_owned(),
67 sender_claimed_keys: Default::default(),
68 session_id: Some("mysessionid9".to_owned()),
69 },
70 verification_state: VerificationState::Verified,
71 });
72
73 let mut builder = EventFactory::new().text_msg(content).room(room_id).sender(*ALICE);
74 if let Some(event_id) = event_id {
75 builder = builder.event_id(event_id);
76 }
77 let event = builder.into_raw_timeline().cast();
78
79 TimelineEvent::from_decrypted(
80 DecryptedRoomEvent { event, encryption_info, unsigned_encryption_info: None },
81 Some(vec![Action::Notify]),
82 )
83}
84
85#[track_caller]
90pub fn check_test_event(event: &TimelineEvent, text: &str) {
91 let actions = event.push_actions().unwrap();
93 assert_eq!(actions.len(), 1);
94 assert_matches!(&actions[0], Action::Notify);
95
96 assert_matches!(&event.kind, TimelineEventKind::Decrypted(d) => {
98 assert_eq!(d.encryption_info.sender, *ALICE);
100 assert_matches!(&d.encryption_info.algorithm_info, AlgorithmInfo::MegolmV1AesSha2 { curve25519_key, .. } => {
101 assert_eq!(curve25519_key, "1337");
102 });
103
104 let deserialized = d.event.deserialize().unwrap();
106 assert_matches!(deserialized, ruma::events::AnyMessageLikeEvent::RoomMessage(msg) => {
107 assert_eq!(msg.as_original().unwrap().content.body(), text);
108 });
109 });
110}
111
112#[allow(async_fn_in_trait)]
117pub trait EventCacheStoreIntegrationTests {
118 async fn test_media_content(&self);
120
121 async fn test_replace_media_key(&self);
123
124 async fn test_handle_updates_and_rebuild_linked_chunk(&self);
127
128 async fn test_linked_chunk_incremental_loading(&self);
131
132 async fn test_rebuild_empty_linked_chunk(&self);
135
136 async fn test_clear_all_linked_chunks(&self);
138
139 async fn test_remove_room(&self);
141
142 async fn test_filter_duplicated_events(&self);
144
145 async fn test_find_event(&self);
147
148 async fn test_find_event_relations(&self);
150
151 async fn test_save_event(&self);
153}
154
155impl EventCacheStoreIntegrationTests for DynEventCacheStore {
156 async fn test_media_content(&self) {
157 let uri = mxc_uri!("mxc://localhost/media");
158 let request_file = MediaRequestParameters {
159 source: MediaSource::Plain(uri.to_owned()),
160 format: MediaFormat::File,
161 };
162 let request_thumbnail = MediaRequestParameters {
163 source: MediaSource::Plain(uri.to_owned()),
164 format: MediaFormat::Thumbnail(MediaThumbnailSettings::with_method(
165 Method::Crop,
166 uint!(100),
167 uint!(100),
168 )),
169 };
170
171 let other_uri = mxc_uri!("mxc://localhost/media-other");
172 let request_other_file = MediaRequestParameters {
173 source: MediaSource::Plain(other_uri.to_owned()),
174 format: MediaFormat::File,
175 };
176
177 let content: Vec<u8> = "hello".into();
178 let thumbnail_content: Vec<u8> = "world".into();
179 let other_content: Vec<u8> = "foo".into();
180
181 assert!(
183 self.get_media_content(&request_file).await.unwrap().is_none(),
184 "unexpected media found"
185 );
186 assert!(
187 self.get_media_content(&request_thumbnail).await.unwrap().is_none(),
188 "media not found"
189 );
190
191 self.add_media_content(&request_file, content.clone(), IgnoreMediaRetentionPolicy::No)
193 .await
194 .expect("adding media failed");
195
196 assert_eq!(
198 self.get_media_content(&request_file).await.unwrap().as_ref(),
199 Some(&content),
200 "media not found though added"
201 );
202 assert_eq!(
203 self.get_media_content_for_uri(uri).await.unwrap().as_ref(),
204 Some(&content),
205 "media not found by URI though added"
206 );
207
208 self.remove_media_content(&request_file).await.expect("removing media failed");
210
211 assert!(
213 self.get_media_content(&request_file).await.unwrap().is_none(),
214 "media still there after removing"
215 );
216 assert!(
217 self.get_media_content_for_uri(uri).await.unwrap().is_none(),
218 "media still found by URI after removing"
219 );
220
221 self.add_media_content(&request_file, content.clone(), IgnoreMediaRetentionPolicy::No)
223 .await
224 .expect("adding media again failed");
225
226 assert_eq!(
227 self.get_media_content(&request_file).await.unwrap().as_ref(),
228 Some(&content),
229 "media not found after adding again"
230 );
231
232 self.add_media_content(
234 &request_thumbnail,
235 thumbnail_content.clone(),
236 IgnoreMediaRetentionPolicy::No,
237 )
238 .await
239 .expect("adding thumbnail failed");
240
241 assert_eq!(
243 self.get_media_content(&request_thumbnail).await.unwrap().as_ref(),
244 Some(&thumbnail_content),
245 "thumbnail not found"
246 );
247
248 assert!(
250 self.get_media_content_for_uri(uri).await.unwrap().is_some(),
251 "media not found by URI though two where added"
252 );
253
254 self.add_media_content(
256 &request_other_file,
257 other_content.clone(),
258 IgnoreMediaRetentionPolicy::No,
259 )
260 .await
261 .expect("adding other media failed");
262
263 assert_eq!(
265 self.get_media_content(&request_other_file).await.unwrap().as_ref(),
266 Some(&other_content),
267 "other file not found"
268 );
269 assert_eq!(
270 self.get_media_content_for_uri(other_uri).await.unwrap().as_ref(),
271 Some(&other_content),
272 "other file not found by URI"
273 );
274
275 self.remove_media_content_for_uri(uri).await.expect("removing all media for uri failed");
277
278 assert!(
279 self.get_media_content(&request_file).await.unwrap().is_none(),
280 "media wasn't removed"
281 );
282 assert!(
283 self.get_media_content(&request_thumbnail).await.unwrap().is_none(),
284 "thumbnail wasn't removed"
285 );
286 assert!(
287 self.get_media_content(&request_other_file).await.unwrap().is_some(),
288 "other media was removed"
289 );
290 assert!(
291 self.get_media_content_for_uri(uri).await.unwrap().is_none(),
292 "media found by URI wasn't removed"
293 );
294 assert!(
295 self.get_media_content_for_uri(other_uri).await.unwrap().is_some(),
296 "other media found by URI was removed"
297 );
298 }
299
300 async fn test_replace_media_key(&self) {
301 let uri = mxc_uri!("mxc://sendqueue.local/tr4n-s4ct-10n1-d");
302 let req = MediaRequestParameters {
303 source: MediaSource::Plain(uri.to_owned()),
304 format: MediaFormat::File,
305 };
306
307 let content = "hello".as_bytes().to_owned();
308
309 assert!(self.get_media_content(&req).await.unwrap().is_none(), "unexpected media found");
311
312 self.add_media_content(&req, content.clone(), IgnoreMediaRetentionPolicy::No)
314 .await
315 .expect("adding media failed");
316
317 assert_eq!(self.get_media_content(&req).await.unwrap().unwrap(), b"hello");
319
320 let new_uri = mxc_uri!("mxc://matrix.org/tr4n-s4ct-10n1-d");
322 let new_req = MediaRequestParameters {
323 source: MediaSource::Plain(new_uri.to_owned()),
324 format: MediaFormat::File,
325 };
326 self.replace_media_key(&req, &new_req)
327 .await
328 .expect("replacing the media request key failed");
329
330 assert!(
332 self.get_media_content(&req).await.unwrap().is_none(),
333 "unexpected media found with the old key"
334 );
335
336 assert_eq!(self.get_media_content(&new_req).await.unwrap().unwrap(), b"hello");
338 }
339
340 async fn test_handle_updates_and_rebuild_linked_chunk(&self) {
341 let room_id = room_id!("!r0:matrix.org");
342 let linked_chunk_id = LinkedChunkId::Room(room_id);
343
344 self.handle_linked_chunk_updates(
345 linked_chunk_id,
346 vec![
347 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
349 Update::PushItems {
351 at: Position::new(CId::new(0), 0),
352 items: vec![
353 make_test_event(room_id, "hello"),
354 make_test_event(room_id, "world"),
355 ],
356 },
357 Update::NewGapChunk {
359 previous: Some(CId::new(0)),
360 new: CId::new(1),
361 next: None,
362 gap: Gap { prev_token: "parmesan".to_owned() },
363 },
364 Update::NewItemsChunk { previous: Some(CId::new(1)), new: CId::new(2), next: None },
366 Update::PushItems {
368 at: Position::new(CId::new(2), 0),
369 items: vec![make_test_event(room_id, "sup")],
370 },
371 ],
372 )
373 .await
374 .unwrap();
375
376 let lc = lazy_loader::from_all_chunks::<3, _, _>(
378 self.load_all_chunks(linked_chunk_id).await.unwrap(),
379 )
380 .unwrap()
381 .unwrap();
382
383 let mut chunks = lc.chunks();
384
385 {
386 let first = chunks.next().unwrap();
387 assert_eq!(first.identifier(), CId::new(0));
390
391 assert_matches!(first.content(), ChunkContent::Items(events) => {
392 assert_eq!(events.len(), 2);
393 check_test_event(&events[0], "hello");
394 check_test_event(&events[1], "world");
395 });
396 }
397
398 {
399 let second = chunks.next().unwrap();
400 assert_eq!(second.identifier(), CId::new(1));
401
402 assert_matches!(second.content(), ChunkContent::Gap(gap) => {
403 assert_eq!(gap.prev_token, "parmesan");
404 });
405 }
406
407 {
408 let third = chunks.next().unwrap();
409 assert_eq!(third.identifier(), CId::new(2));
410
411 assert_matches!(third.content(), ChunkContent::Items(events) => {
412 assert_eq!(events.len(), 1);
413 check_test_event(&events[0], "sup");
414 });
415 }
416
417 assert!(chunks.next().is_none());
418 }
419
420 async fn test_linked_chunk_incremental_loading(&self) {
421 let room_id = room_id!("!r0:matrix.org");
422 let linked_chunk_id = LinkedChunkId::Room(room_id);
423 let event = |msg: &str| make_test_event(room_id, msg);
424
425 {
427 let (last_chunk, chunk_identifier_generator) =
428 self.load_last_chunk(linked_chunk_id).await.unwrap();
429
430 assert!(last_chunk.is_none());
431 assert_eq!(chunk_identifier_generator.current(), 0);
432 }
433
434 self.handle_linked_chunk_updates(
435 linked_chunk_id,
436 vec![
437 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
439 Update::PushItems {
441 at: Position::new(CId::new(0), 0),
442 items: vec![event("a"), event("b")],
443 },
444 Update::NewGapChunk {
446 previous: Some(CId::new(0)),
447 new: CId::new(1),
448 next: None,
449 gap: Gap { prev_token: "morbier".to_owned() },
450 },
451 Update::NewItemsChunk { previous: Some(CId::new(1)), new: CId::new(2), next: None },
453 Update::PushItems {
455 at: Position::new(CId::new(2), 0),
456 items: vec![event("c"), event("d"), event("e")],
457 },
458 ],
459 )
460 .await
461 .unwrap();
462
463 let mut linked_chunk = {
465 let (last_chunk, chunk_identifier_generator) =
466 self.load_last_chunk(linked_chunk_id).await.unwrap();
467
468 assert_eq!(chunk_identifier_generator.current(), 2);
469
470 let linked_chunk = lazy_loader::from_last_chunk::<DEFAULT_CHUNK_CAPACITY, _, _>(
471 last_chunk,
472 chunk_identifier_generator,
473 )
474 .unwrap() .unwrap(); let mut rchunks = linked_chunk.rchunks();
478
479 assert_matches!(rchunks.next(), Some(chunk) => {
481 assert_eq!(chunk.identifier(), 2);
482 assert_eq!(chunk.lazy_previous(), Some(CId::new(1)));
483
484 assert_matches!(chunk.content(), ChunkContent::Items(events) => {
485 assert_eq!(events.len(), 3);
486 check_test_event(&events[0], "c");
487 check_test_event(&events[1], "d");
488 check_test_event(&events[2], "e");
489 });
490 });
491
492 assert!(rchunks.next().is_none());
493
494 linked_chunk
495 };
496
497 {
499 let first_chunk = linked_chunk.chunks().next().unwrap().identifier();
500 let previous_chunk =
501 self.load_previous_chunk(linked_chunk_id, first_chunk).await.unwrap().unwrap();
502
503 lazy_loader::insert_new_first_chunk(&mut linked_chunk, previous_chunk).unwrap();
504
505 let mut rchunks = linked_chunk.rchunks();
506
507 assert_matches!(rchunks.next(), Some(chunk) => {
509 assert_eq!(chunk.identifier(), 2);
510 assert!(chunk.lazy_previous().is_none());
511
512 assert_matches!(chunk.content(), ChunkContent::Items(events) => {
514 assert_eq!(events.len(), 3);
515 check_test_event(&events[0], "c");
516 check_test_event(&events[1], "d");
517 check_test_event(&events[2], "e");
518 });
519 });
520
521 assert_matches!(rchunks.next(), Some(chunk) => {
523 assert_eq!(chunk.identifier(), 1);
524 assert_eq!(chunk.lazy_previous(), Some(CId::new(0)));
525
526 assert_matches!(chunk.content(), ChunkContent::Gap(gap) => {
527 assert_eq!(gap.prev_token, "morbier");
528 });
529 });
530
531 assert!(rchunks.next().is_none());
532 }
533
534 {
536 let first_chunk = linked_chunk.chunks().next().unwrap().identifier();
537 let previous_chunk =
538 self.load_previous_chunk(linked_chunk_id, first_chunk).await.unwrap().unwrap();
539
540 lazy_loader::insert_new_first_chunk(&mut linked_chunk, previous_chunk).unwrap();
541
542 let mut rchunks = linked_chunk.rchunks();
543
544 assert_matches!(rchunks.next(), Some(chunk) => {
546 assert_eq!(chunk.identifier(), 2);
547 assert!(chunk.lazy_previous().is_none());
548
549 assert_matches!(chunk.content(), ChunkContent::Items(events) => {
551 assert_eq!(events.len(), 3);
552 check_test_event(&events[0], "c");
553 check_test_event(&events[1], "d");
554 check_test_event(&events[2], "e");
555 });
556 });
557
558 assert_matches!(rchunks.next(), Some(chunk) => {
560 assert_eq!(chunk.identifier(), 1);
561 assert!(chunk.lazy_previous().is_none());
562
563 assert_matches!(chunk.content(), ChunkContent::Gap(gap) => {
565 assert_eq!(gap.prev_token, "morbier");
566 });
567 });
568
569 assert_matches!(rchunks.next(), Some(chunk) => {
571 assert_eq!(chunk.identifier(), 0);
572 assert!(chunk.lazy_previous().is_none());
573
574 assert_matches!(chunk.content(), ChunkContent::Items(events) => {
575 assert_eq!(events.len(), 2);
576 check_test_event(&events[0], "a");
577 check_test_event(&events[1], "b");
578 });
579 });
580
581 assert!(rchunks.next().is_none());
582 }
583
584 {
586 let first_chunk = linked_chunk.chunks().next().unwrap().identifier();
587 let previous_chunk =
588 self.load_previous_chunk(linked_chunk_id, first_chunk).await.unwrap();
589
590 assert!(previous_chunk.is_none());
591 }
592
593 {
596 let mut chunks = linked_chunk.chunks();
597
598 assert_matches!(chunks.next(), Some(chunk) => {
600 assert_eq!(chunk.identifier(), 0);
601 assert!(chunk.lazy_previous().is_none());
602
603 assert_matches!(chunk.content(), ChunkContent::Items(events) => {
604 assert_eq!(events.len(), 2);
605 check_test_event(&events[0], "a");
606 check_test_event(&events[1], "b");
607 });
608 });
609
610 assert_matches!(chunks.next(), Some(chunk) => {
612 assert_eq!(chunk.identifier(), 1);
613 assert!(chunk.lazy_previous().is_none());
614
615 assert_matches!(chunk.content(), ChunkContent::Gap(gap) => {
616 assert_eq!(gap.prev_token, "morbier");
617 });
618 });
619
620 assert_matches!(chunks.next(), Some(chunk) => {
622 assert_eq!(chunk.identifier(), 2);
623 assert!(chunk.lazy_previous().is_none());
624
625 assert_matches!(chunk.content(), ChunkContent::Items(events) => {
626 assert_eq!(events.len(), 3);
627 check_test_event(&events[0], "c");
628 check_test_event(&events[1], "d");
629 check_test_event(&events[2], "e");
630 });
631 });
632
633 assert!(chunks.next().is_none());
634 }
635 }
636
637 async fn test_rebuild_empty_linked_chunk(&self) {
638 let linked_chunk = lazy_loader::from_all_chunks::<3, _, _>(
640 self.load_all_chunks(LinkedChunkId::Room(&DEFAULT_TEST_ROOM_ID)).await.unwrap(),
641 )
642 .unwrap();
643 assert!(linked_chunk.is_none());
644 }
645
646 async fn test_clear_all_linked_chunks(&self) {
647 let r0 = room_id!("!r0:matrix.org");
648 let linked_chunk_id0 = LinkedChunkId::Room(r0);
649 let r1 = room_id!("!r1:matrix.org");
650 let linked_chunk_id1 = LinkedChunkId::Room(r1);
651
652 self.handle_linked_chunk_updates(
654 linked_chunk_id0,
655 vec![
656 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
658 Update::PushItems {
660 at: Position::new(CId::new(0), 0),
661 items: vec![make_test_event(r0, "hello"), make_test_event(r0, "world")],
662 },
663 ],
664 )
665 .await
666 .unwrap();
667
668 self.handle_linked_chunk_updates(
670 linked_chunk_id1,
671 vec![
672 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
674 Update::NewGapChunk {
676 previous: Some(CId::new(0)),
677 new: CId::new(1),
678 next: None,
679 gap: Gap { prev_token: "bleu d'auvergne".to_owned() },
680 },
681 Update::NewItemsChunk { previous: Some(CId::new(1)), new: CId::new(2), next: None },
683 Update::PushItems {
685 at: Position::new(CId::new(2), 0),
686 items: vec![make_test_event(r0, "yummy")],
687 },
688 ],
689 )
690 .await
691 .unwrap();
692
693 assert!(lazy_loader::from_all_chunks::<3, _, _>(
695 self.load_all_chunks(linked_chunk_id0).await.unwrap()
696 )
697 .unwrap()
698 .is_some());
699 assert!(lazy_loader::from_all_chunks::<3, _, _>(
700 self.load_all_chunks(linked_chunk_id1).await.unwrap()
701 )
702 .unwrap()
703 .is_some());
704
705 self.clear_all_linked_chunks().await.unwrap();
707
708 assert!(lazy_loader::from_all_chunks::<3, _, _>(
710 self.load_all_chunks(linked_chunk_id0).await.unwrap()
711 )
712 .unwrap()
713 .is_none());
714 assert!(lazy_loader::from_all_chunks::<3, _, _>(
715 self.load_all_chunks(linked_chunk_id1).await.unwrap()
716 )
717 .unwrap()
718 .is_none());
719 }
720
721 async fn test_remove_room(&self) {
722 let r0 = room_id!("!r0:matrix.org");
723 let linked_chunk_id0 = LinkedChunkId::Room(r0);
724 let r1 = room_id!("!r1:matrix.org");
725 let linked_chunk_id1 = LinkedChunkId::Room(r1);
726
727 self.handle_linked_chunk_updates(
729 linked_chunk_id0,
730 vec![
731 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
733 Update::PushItems {
735 at: Position::new(CId::new(0), 0),
736 items: vec![make_test_event(r0, "hello"), make_test_event(r0, "world")],
737 },
738 ],
739 )
740 .await
741 .unwrap();
742
743 self.handle_linked_chunk_updates(
745 linked_chunk_id1,
746 vec![
747 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
749 Update::PushItems {
751 at: Position::new(CId::new(0), 0),
752 items: vec![make_test_event(r0, "yummy")],
753 },
754 ],
755 )
756 .await
757 .unwrap();
758
759 self.remove_room(r0).await.unwrap();
761
762 let r0_linked_chunk = self.load_all_chunks(linked_chunk_id0).await.unwrap();
764 assert!(r0_linked_chunk.is_empty());
765
766 let r1_linked_chunk = self.load_all_chunks(linked_chunk_id1).await.unwrap();
768 assert!(!r1_linked_chunk.is_empty());
769 }
770
771 async fn test_filter_duplicated_events(&self) {
772 let room_id = room_id!("!r0:matrix.org");
773 let linked_chunk_id = LinkedChunkId::Room(room_id);
774 let another_room_id = room_id!("!r1:matrix.org");
775 let another_linked_chunk_id = LinkedChunkId::Room(another_room_id);
776 let event = |msg: &str| make_test_event(room_id, msg);
777
778 let event_comte = event("comté");
779 let event_brigand = event("brigand du jorat");
780 let event_raclette = event("raclette");
781 let event_morbier = event("morbier");
782 let event_gruyere = event("gruyère");
783 let event_tome = event("tome");
784 let event_mont_dor = event("mont d'or");
785
786 self.handle_linked_chunk_updates(
787 linked_chunk_id,
788 vec![
789 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
790 Update::PushItems {
791 at: Position::new(CId::new(0), 0),
792 items: vec![event_comte.clone(), event_brigand.clone()],
793 },
794 Update::NewGapChunk {
795 previous: Some(CId::new(0)),
796 new: CId::new(1),
797 next: None,
798 gap: Gap { prev_token: "brillat-savarin".to_owned() },
799 },
800 Update::NewItemsChunk { previous: Some(CId::new(1)), new: CId::new(2), next: None },
801 Update::PushItems {
802 at: Position::new(CId::new(2), 0),
803 items: vec![event_morbier.clone(), event_mont_dor.clone()],
804 },
805 ],
806 )
807 .await
808 .unwrap();
809
810 self.handle_linked_chunk_updates(
813 another_linked_chunk_id,
814 vec![
815 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
816 Update::PushItems {
817 at: Position::new(CId::new(0), 0),
818 items: vec![event_tome.clone()],
819 },
820 ],
821 )
822 .await
823 .unwrap();
824
825 let duplicated_events = self
826 .filter_duplicated_events(
827 linked_chunk_id,
828 vec![
829 event_comte.event_id().unwrap().to_owned(),
830 event_raclette.event_id().unwrap().to_owned(),
831 event_morbier.event_id().unwrap().to_owned(),
832 event_gruyere.event_id().unwrap().to_owned(),
833 event_tome.event_id().unwrap().to_owned(),
834 event_mont_dor.event_id().unwrap().to_owned(),
835 ],
836 )
837 .await
838 .unwrap();
839
840 assert_eq!(duplicated_events.len(), 3);
841 assert_eq!(
842 duplicated_events[0],
843 (event_comte.event_id().unwrap(), Position::new(CId::new(0), 0))
844 );
845 assert_eq!(
846 duplicated_events[1],
847 (event_morbier.event_id().unwrap(), Position::new(CId::new(2), 0))
848 );
849 assert_eq!(
850 duplicated_events[2],
851 (event_mont_dor.event_id().unwrap(), Position::new(CId::new(2), 1))
852 );
853 }
854
855 async fn test_find_event(&self) {
856 let room_id = room_id!("!r0:matrix.org");
857 let another_room_id = room_id!("!r1:matrix.org");
858 let another_linked_chunk_id = LinkedChunkId::Room(another_room_id);
859 let event = |msg: &str| make_test_event(room_id, msg);
860
861 let event_comte = event("comté");
862 let event_gruyere = event("gruyère");
863
864 self.handle_linked_chunk_updates(
866 LinkedChunkId::Room(room_id),
867 vec![
868 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
869 Update::PushItems {
870 at: Position::new(CId::new(0), 0),
871 items: vec![event_comte.clone()],
872 },
873 ],
874 )
875 .await
876 .unwrap();
877
878 self.handle_linked_chunk_updates(
880 another_linked_chunk_id,
881 vec![
882 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
883 Update::PushItems {
884 at: Position::new(CId::new(0), 0),
885 items: vec![event_gruyere.clone()],
886 },
887 ],
888 )
889 .await
890 .unwrap();
891
892 let event = self
894 .find_event(room_id, event_comte.event_id().unwrap().as_ref())
895 .await
896 .expect("failed to query for finding an event")
897 .expect("failed to find an event");
898
899 assert_eq!(event.event_id(), event_comte.event_id());
900
901 assert!(self
903 .find_event(room_id, event_gruyere.event_id().unwrap().as_ref())
904 .await
905 .expect("failed to query for finding an event")
906 .is_none());
907
908 self.clear_all_linked_chunks().await.expect("failed to clear all rooms chunks");
910 assert!(self
911 .find_event(room_id, event_comte.event_id().unwrap().as_ref())
912 .await
913 .expect("failed to query for finding an event")
914 .is_none());
915 }
916
917 async fn test_find_event_relations(&self) {
918 let room_id = room_id!("!r0:matrix.org");
919 let another_room_id = room_id!("!r1:matrix.org");
920
921 let f = EventFactory::new().room(room_id).sender(*ALICE);
922
923 let eid1 = event_id!("$event1:matrix.org");
925 let e1 = f.text_msg("comter").event_id(eid1).into_event();
926
927 let edit_eid1 = event_id!("$edit_event1:matrix.org");
928 let edit_e1 = f
929 .text_msg("* comté")
930 .event_id(edit_eid1)
931 .edit(eid1, RoomMessageEventContentWithoutRelation::text_plain("comté"))
932 .into_event();
933
934 let reaction_eid1 = event_id!("$reaction_event1:matrix.org");
935 let reaction_e1 = f.reaction(eid1, "👍").event_id(reaction_eid1).into_event();
936
937 let eid2 = event_id!("$event2:matrix.org");
938 let e2 = f.text_msg("galette saucisse").event_id(eid2).into_event();
939
940 let f = f.room(another_room_id);
942
943 let eid3 = event_id!("$event3:matrix.org");
944 let e3 = f.text_msg("gruyère").event_id(eid3).into_event();
945
946 let reaction_eid3 = event_id!("$reaction_event3:matrix.org");
947 let reaction_e3 = f.reaction(eid3, "👍").event_id(reaction_eid3).into_event();
948
949 self.save_event(room_id, e1).await.unwrap();
951 self.save_event(room_id, edit_e1).await.unwrap();
952 self.save_event(room_id, reaction_e1).await.unwrap();
953 self.save_event(room_id, e2).await.unwrap();
954 self.save_event(another_room_id, e3).await.unwrap();
955 self.save_event(another_room_id, reaction_e3).await.unwrap();
956
957 let relations = self.find_event_relations(room_id, eid1, None).await.unwrap();
959 assert_eq!(relations.len(), 2);
960 assert!(relations.iter().any(|r| r.event_id().as_deref() == Some(edit_eid1)));
961 assert!(relations.iter().any(|r| r.event_id().as_deref() == Some(reaction_eid1)));
962
963 let relations = self
965 .find_event_relations(room_id, eid1, Some(&[RelationType::Replacement]))
966 .await
967 .unwrap();
968 assert_eq!(relations.len(), 1);
969 assert_eq!(relations[0].event_id().as_deref(), Some(edit_eid1));
970
971 let relations = self
972 .find_event_relations(
973 room_id,
974 eid1,
975 Some(&[RelationType::Replacement, RelationType::Annotation]),
976 )
977 .await
978 .unwrap();
979 assert_eq!(relations.len(), 2);
980 assert!(relations.iter().any(|r| r.event_id().as_deref() == Some(edit_eid1)));
981 assert!(relations.iter().any(|r| r.event_id().as_deref() == Some(reaction_eid1)));
982
983 let relations = self
985 .find_event_relations(another_room_id, eid1, Some(&[RelationType::Replacement]))
986 .await
987 .unwrap();
988 assert!(relations.is_empty());
989 }
990
991 async fn test_save_event(&self) {
992 let room_id = room_id!("!r0:matrix.org");
993 let another_room_id = room_id!("!r1:matrix.org");
994
995 let event = |msg: &str| make_test_event(room_id, msg);
996 let event_comte = event("comté");
997 let event_gruyere = event("gruyère");
998
999 self.save_event(room_id, event_comte.clone()).await.unwrap();
1001
1002 self.save_event(another_room_id, event_gruyere.clone()).await.unwrap();
1004
1005 let event = self
1007 .find_event(room_id, event_comte.event_id().unwrap().as_ref())
1008 .await
1009 .expect("failed to query for finding an event")
1010 .expect("failed to find an event");
1011 assert_eq!(event.event_id(), event_comte.event_id());
1012
1013 let event = self
1014 .find_event(another_room_id, event_gruyere.event_id().unwrap().as_ref())
1015 .await
1016 .expect("failed to query for finding an event")
1017 .expect("failed to find an event");
1018 assert_eq!(event.event_id(), event_gruyere.event_id());
1019
1020 assert!(self
1022 .find_event(another_room_id, event_comte.event_id().unwrap().as_ref())
1023 .await
1024 .expect("failed to query for finding an event")
1025 .is_none());
1026 assert!(self
1027 .find_event(room_id, event_gruyere.event_id().unwrap().as_ref())
1028 .await
1029 .expect("failed to query for finding an event")
1030 .is_none());
1031 }
1032}
1033
1034#[allow(unused_macros, unused_extern_crates)]
1062#[macro_export]
1063macro_rules! event_cache_store_integration_tests {
1064 () => {
1065 mod event_cache_store_integration_tests {
1066 use matrix_sdk_test::async_test;
1067 use $crate::event_cache::store::{
1068 EventCacheStoreIntegrationTests, IntoEventCacheStore,
1069 };
1070
1071 use super::get_event_cache_store;
1072
1073 #[async_test]
1074 async fn test_media_content() {
1075 let event_cache_store =
1076 get_event_cache_store().await.unwrap().into_event_cache_store();
1077 event_cache_store.test_media_content().await;
1078 }
1079
1080 #[async_test]
1081 async fn test_replace_media_key() {
1082 let event_cache_store =
1083 get_event_cache_store().await.unwrap().into_event_cache_store();
1084 event_cache_store.test_replace_media_key().await;
1085 }
1086
1087 #[async_test]
1088 async fn test_handle_updates_and_rebuild_linked_chunk() {
1089 let event_cache_store =
1090 get_event_cache_store().await.unwrap().into_event_cache_store();
1091 event_cache_store.test_handle_updates_and_rebuild_linked_chunk().await;
1092 }
1093
1094 #[async_test]
1095 async fn test_linked_chunk_incremental_loading() {
1096 let event_cache_store =
1097 get_event_cache_store().await.unwrap().into_event_cache_store();
1098 event_cache_store.test_linked_chunk_incremental_loading().await;
1099 }
1100
1101 #[async_test]
1102 async fn test_rebuild_empty_linked_chunk() {
1103 let event_cache_store =
1104 get_event_cache_store().await.unwrap().into_event_cache_store();
1105 event_cache_store.test_rebuild_empty_linked_chunk().await;
1106 }
1107
1108 #[async_test]
1109 async fn test_clear_all_linked_chunks() {
1110 let event_cache_store =
1111 get_event_cache_store().await.unwrap().into_event_cache_store();
1112 event_cache_store.test_clear_all_linked_chunks().await;
1113 }
1114
1115 #[async_test]
1116 async fn test_remove_room() {
1117 let event_cache_store =
1118 get_event_cache_store().await.unwrap().into_event_cache_store();
1119 event_cache_store.test_remove_room().await;
1120 }
1121
1122 #[async_test]
1123 async fn test_filter_duplicated_events() {
1124 let event_cache_store =
1125 get_event_cache_store().await.unwrap().into_event_cache_store();
1126 event_cache_store.test_filter_duplicated_events().await;
1127 }
1128
1129 #[async_test]
1130 async fn test_find_event() {
1131 let event_cache_store =
1132 get_event_cache_store().await.unwrap().into_event_cache_store();
1133 event_cache_store.test_find_event().await;
1134 }
1135
1136 #[async_test]
1137 async fn test_find_event_relations() {
1138 let event_cache_store =
1139 get_event_cache_store().await.unwrap().into_event_cache_store();
1140 event_cache_store.test_find_event_relations().await;
1141 }
1142
1143 #[async_test]
1144 async fn test_save_event() {
1145 let event_cache_store =
1146 get_event_cache_store().await.unwrap().into_event_cache_store();
1147 event_cache_store.test_save_event().await;
1148 }
1149 }
1150 };
1151}
1152
1153#[allow(unused_macros)]
1156#[macro_export]
1157macro_rules! event_cache_store_integration_tests_time {
1158 () => {
1159 #[cfg(not(target_family = "wasm"))]
1160 mod event_cache_store_integration_tests_time {
1161 use std::time::Duration;
1162
1163 use matrix_sdk_test::async_test;
1164 use $crate::event_cache::store::IntoEventCacheStore;
1165
1166 use super::get_event_cache_store;
1167
1168 #[async_test]
1169 async fn test_lease_locks() {
1170 let store = get_event_cache_store().await.unwrap().into_event_cache_store();
1171
1172 let acquired0 = store.try_take_leased_lock(0, "key", "alice").await.unwrap();
1173 assert!(acquired0);
1174
1175 let acquired2 = store.try_take_leased_lock(300, "key", "alice").await.unwrap();
1177 assert!(acquired2);
1178
1179 let acquired3 = store.try_take_leased_lock(300, "key", "alice").await.unwrap();
1181 assert!(acquired3);
1182
1183 let acquired4 = store.try_take_leased_lock(300, "key", "bob").await.unwrap();
1185 assert!(!acquired4);
1186
1187 let acquired5 = store.try_take_leased_lock(300, "key", "bob").await.unwrap();
1189 assert!(!acquired5);
1190
1191 tokio::time::sleep(Duration::from_millis(50)).await;
1193
1194 let acquired55 = store.try_take_leased_lock(300, "key", "bob").await.unwrap();
1196 assert!(!acquired55);
1197
1198 tokio::time::sleep(Duration::from_millis(250)).await;
1200
1201 let acquired6 = store.try_take_leased_lock(0, "key", "bob").await.unwrap();
1203 assert!(acquired6);
1204
1205 tokio::time::sleep(Duration::from_millis(1)).await;
1206
1207 let acquired7 = store.try_take_leased_lock(0, "key", "alice").await.unwrap();
1209 assert!(acquired7);
1210
1211 tokio::time::sleep(Duration::from_millis(1)).await;
1212
1213 let acquired8 = store.try_take_leased_lock(300, "key", "bob").await.unwrap();
1215 assert!(acquired8);
1216
1217 let acquired9 = store.try_take_leased_lock(300, "key", "alice").await.unwrap();
1219 assert!(!acquired9);
1220
1221 let acquired10 = store.try_take_leased_lock(300, "key", "bob").await.unwrap();
1223 assert!(acquired10);
1224 }
1225 }
1226 };
1227}