1use assert_matches::assert_matches;
18use async_trait::async_trait;
19use matrix_sdk_common::{
20 deserialized_responses::{
21 AlgorithmInfo, DecryptedRoomEvent, EncryptionInfo, TimelineEvent, TimelineEventKind,
22 VerificationState,
23 },
24 linked_chunk::{lazy_loader, ChunkContent, ChunkIdentifier as CId, Position, Update},
25};
26use matrix_sdk_test::{event_factory::EventFactory, ALICE, DEFAULT_TEST_ROOM_ID};
27use ruma::{
28 api::client::media::get_content_thumbnail::v3::Method,
29 event_id,
30 events::{
31 relation::RelationType,
32 room::{message::RoomMessageEventContentWithoutRelation, MediaSource},
33 },
34 mxc_uri,
35 push::Action,
36 room_id, uint, EventId, RoomId,
37};
38
39use super::{media::IgnoreMediaRetentionPolicy, DynEventCacheStore};
40use crate::{
41 event_cache::{store::DEFAULT_CHUNK_CAPACITY, Gap},
42 media::{MediaFormat, MediaRequestParameters, MediaThumbnailSettings},
43};
44
45pub fn make_test_event(room_id: &RoomId, content: &str) -> TimelineEvent {
50 make_test_event_with_event_id(room_id, content, None)
51}
52
53pub fn make_test_event_with_event_id(
55 room_id: &RoomId,
56 content: &str,
57 event_id: Option<&EventId>,
58) -> TimelineEvent {
59 let encryption_info = EncryptionInfo {
60 sender: (*ALICE).into(),
61 sender_device: None,
62 algorithm_info: AlgorithmInfo::MegolmV1AesSha2 {
63 curve25519_key: "1337".to_owned(),
64 sender_claimed_keys: Default::default(),
65 },
66 verification_state: VerificationState::Verified,
67 session_id: Some("mysessionid9".to_owned()),
68 };
69
70 let mut builder = EventFactory::new().text_msg(content).room(room_id).sender(*ALICE);
71 if let Some(event_id) = event_id {
72 builder = builder.event_id(event_id);
73 }
74 let event = builder.into_raw_timeline().cast();
75
76 TimelineEvent {
77 kind: TimelineEventKind::Decrypted(DecryptedRoomEvent {
78 event,
79 encryption_info,
80 unsigned_encryption_info: None,
81 }),
82 push_actions: Some(vec![Action::Notify]),
83 }
84}
85
86#[track_caller]
91pub fn check_test_event(event: &TimelineEvent, text: &str) {
92 let actions = event.push_actions.as_ref().unwrap();
94 assert_eq!(actions.len(), 1);
95 assert_matches!(&actions[0], Action::Notify);
96
97 assert_matches!(&event.kind, TimelineEventKind::Decrypted(d) => {
99 assert_eq!(d.encryption_info.sender, *ALICE);
101 assert_matches!(&d.encryption_info.algorithm_info, AlgorithmInfo::MegolmV1AesSha2 { curve25519_key, .. } => {
102 assert_eq!(curve25519_key, "1337");
103 });
104
105 let deserialized = d.event.deserialize().unwrap();
107 assert_matches!(deserialized, ruma::events::AnyMessageLikeEvent::RoomMessage(msg) => {
108 assert_eq!(msg.as_original().unwrap().content.body(), text);
109 });
110 });
111}
112
113#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
118#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
119pub trait EventCacheStoreIntegrationTests {
120 async fn test_media_content(&self);
122
123 async fn test_replace_media_key(&self);
125
126 async fn test_handle_updates_and_rebuild_linked_chunk(&self);
129
130 async fn test_linked_chunk_incremental_loading(&self);
133
134 async fn test_rebuild_empty_linked_chunk(&self);
137
138 async fn test_clear_all_rooms_chunks(&self);
140
141 async fn test_remove_room(&self);
143
144 async fn test_filter_duplicated_events(&self);
146
147 async fn test_find_event(&self);
149
150 async fn test_find_event_relations(&self);
152
153 async fn test_save_event(&self);
155}
156
157#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
158#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
159impl EventCacheStoreIntegrationTests for DynEventCacheStore {
160 async fn test_media_content(&self) {
161 let uri = mxc_uri!("mxc://localhost/media");
162 let request_file = MediaRequestParameters {
163 source: MediaSource::Plain(uri.to_owned()),
164 format: MediaFormat::File,
165 };
166 let request_thumbnail = MediaRequestParameters {
167 source: MediaSource::Plain(uri.to_owned()),
168 format: MediaFormat::Thumbnail(MediaThumbnailSettings::with_method(
169 Method::Crop,
170 uint!(100),
171 uint!(100),
172 )),
173 };
174
175 let other_uri = mxc_uri!("mxc://localhost/media-other");
176 let request_other_file = MediaRequestParameters {
177 source: MediaSource::Plain(other_uri.to_owned()),
178 format: MediaFormat::File,
179 };
180
181 let content: Vec<u8> = "hello".into();
182 let thumbnail_content: Vec<u8> = "world".into();
183 let other_content: Vec<u8> = "foo".into();
184
185 assert!(
187 self.get_media_content(&request_file).await.unwrap().is_none(),
188 "unexpected media found"
189 );
190 assert!(
191 self.get_media_content(&request_thumbnail).await.unwrap().is_none(),
192 "media not found"
193 );
194
195 self.add_media_content(&request_file, content.clone(), IgnoreMediaRetentionPolicy::No)
197 .await
198 .expect("adding media failed");
199
200 assert_eq!(
202 self.get_media_content(&request_file).await.unwrap().as_ref(),
203 Some(&content),
204 "media not found though added"
205 );
206 assert_eq!(
207 self.get_media_content_for_uri(uri).await.unwrap().as_ref(),
208 Some(&content),
209 "media not found by URI though added"
210 );
211
212 self.remove_media_content(&request_file).await.expect("removing media failed");
214
215 assert!(
217 self.get_media_content(&request_file).await.unwrap().is_none(),
218 "media still there after removing"
219 );
220 assert!(
221 self.get_media_content_for_uri(uri).await.unwrap().is_none(),
222 "media still found by URI after removing"
223 );
224
225 self.add_media_content(&request_file, content.clone(), IgnoreMediaRetentionPolicy::No)
227 .await
228 .expect("adding media again failed");
229
230 assert_eq!(
231 self.get_media_content(&request_file).await.unwrap().as_ref(),
232 Some(&content),
233 "media not found after adding again"
234 );
235
236 self.add_media_content(
238 &request_thumbnail,
239 thumbnail_content.clone(),
240 IgnoreMediaRetentionPolicy::No,
241 )
242 .await
243 .expect("adding thumbnail failed");
244
245 assert_eq!(
247 self.get_media_content(&request_thumbnail).await.unwrap().as_ref(),
248 Some(&thumbnail_content),
249 "thumbnail not found"
250 );
251
252 assert!(
254 self.get_media_content_for_uri(uri).await.unwrap().is_some(),
255 "media not found by URI though two where added"
256 );
257
258 self.add_media_content(
260 &request_other_file,
261 other_content.clone(),
262 IgnoreMediaRetentionPolicy::No,
263 )
264 .await
265 .expect("adding other media failed");
266
267 assert_eq!(
269 self.get_media_content(&request_other_file).await.unwrap().as_ref(),
270 Some(&other_content),
271 "other file not found"
272 );
273 assert_eq!(
274 self.get_media_content_for_uri(other_uri).await.unwrap().as_ref(),
275 Some(&other_content),
276 "other file not found by URI"
277 );
278
279 self.remove_media_content_for_uri(uri).await.expect("removing all media for uri failed");
281
282 assert!(
283 self.get_media_content(&request_file).await.unwrap().is_none(),
284 "media wasn't removed"
285 );
286 assert!(
287 self.get_media_content(&request_thumbnail).await.unwrap().is_none(),
288 "thumbnail wasn't removed"
289 );
290 assert!(
291 self.get_media_content(&request_other_file).await.unwrap().is_some(),
292 "other media was removed"
293 );
294 assert!(
295 self.get_media_content_for_uri(uri).await.unwrap().is_none(),
296 "media found by URI wasn't removed"
297 );
298 assert!(
299 self.get_media_content_for_uri(other_uri).await.unwrap().is_some(),
300 "other media found by URI was removed"
301 );
302 }
303
304 async fn test_replace_media_key(&self) {
305 let uri = mxc_uri!("mxc://sendqueue.local/tr4n-s4ct-10n1-d");
306 let req = MediaRequestParameters {
307 source: MediaSource::Plain(uri.to_owned()),
308 format: MediaFormat::File,
309 };
310
311 let content = "hello".as_bytes().to_owned();
312
313 assert!(self.get_media_content(&req).await.unwrap().is_none(), "unexpected media found");
315
316 self.add_media_content(&req, content.clone(), IgnoreMediaRetentionPolicy::No)
318 .await
319 .expect("adding media failed");
320
321 assert_eq!(self.get_media_content(&req).await.unwrap().unwrap(), b"hello");
323
324 let new_uri = mxc_uri!("mxc://matrix.org/tr4n-s4ct-10n1-d");
326 let new_req = MediaRequestParameters {
327 source: MediaSource::Plain(new_uri.to_owned()),
328 format: MediaFormat::File,
329 };
330 self.replace_media_key(&req, &new_req)
331 .await
332 .expect("replacing the media request key failed");
333
334 assert!(
336 self.get_media_content(&req).await.unwrap().is_none(),
337 "unexpected media found with the old key"
338 );
339
340 assert_eq!(self.get_media_content(&new_req).await.unwrap().unwrap(), b"hello");
342 }
343
344 async fn test_handle_updates_and_rebuild_linked_chunk(&self) {
345 let room_id = room_id!("!r0:matrix.org");
346
347 self.handle_linked_chunk_updates(
348 room_id,
349 vec![
350 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
352 Update::PushItems {
354 at: Position::new(CId::new(0), 0),
355 items: vec![
356 make_test_event(room_id, "hello"),
357 make_test_event(room_id, "world"),
358 ],
359 },
360 Update::NewGapChunk {
362 previous: Some(CId::new(0)),
363 new: CId::new(1),
364 next: None,
365 gap: Gap { prev_token: "parmesan".to_owned() },
366 },
367 Update::NewItemsChunk { previous: Some(CId::new(1)), new: CId::new(2), next: None },
369 Update::PushItems {
371 at: Position::new(CId::new(2), 0),
372 items: vec![make_test_event(room_id, "sup")],
373 },
374 ],
375 )
376 .await
377 .unwrap();
378
379 let lc =
381 lazy_loader::from_all_chunks::<3, _, _>(self.load_all_chunks(room_id).await.unwrap())
382 .unwrap()
383 .unwrap();
384
385 let mut chunks = lc.chunks();
386
387 {
388 let first = chunks.next().unwrap();
389 assert_eq!(first.identifier(), CId::new(0));
392
393 assert_matches!(first.content(), ChunkContent::Items(events) => {
394 assert_eq!(events.len(), 2);
395 check_test_event(&events[0], "hello");
396 check_test_event(&events[1], "world");
397 });
398 }
399
400 {
401 let second = chunks.next().unwrap();
402 assert_eq!(second.identifier(), CId::new(1));
403
404 assert_matches!(second.content(), ChunkContent::Gap(gap) => {
405 assert_eq!(gap.prev_token, "parmesan");
406 });
407 }
408
409 {
410 let third = chunks.next().unwrap();
411 assert_eq!(third.identifier(), CId::new(2));
412
413 assert_matches!(third.content(), ChunkContent::Items(events) => {
414 assert_eq!(events.len(), 1);
415 check_test_event(&events[0], "sup");
416 });
417 }
418
419 assert!(chunks.next().is_none());
420 }
421
422 async fn test_linked_chunk_incremental_loading(&self) {
423 let room_id = room_id!("!r0:matrix.org");
424 let event = |msg: &str| make_test_event(room_id, msg);
425
426 {
428 let (last_chunk, chunk_identifier_generator) =
429 self.load_last_chunk(room_id).await.unwrap();
430
431 assert!(last_chunk.is_none());
432 assert_eq!(chunk_identifier_generator.current(), 0);
433 }
434
435 self.handle_linked_chunk_updates(
436 room_id,
437 vec![
438 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
440 Update::PushItems {
442 at: Position::new(CId::new(0), 0),
443 items: vec![event("a"), event("b")],
444 },
445 Update::NewGapChunk {
447 previous: Some(CId::new(0)),
448 new: CId::new(1),
449 next: None,
450 gap: Gap { prev_token: "morbier".to_owned() },
451 },
452 Update::NewItemsChunk { previous: Some(CId::new(1)), new: CId::new(2), next: None },
454 Update::PushItems {
456 at: Position::new(CId::new(2), 0),
457 items: vec![event("c"), event("d"), event("e")],
458 },
459 ],
460 )
461 .await
462 .unwrap();
463
464 let mut linked_chunk = {
466 let (last_chunk, chunk_identifier_generator) =
467 self.load_last_chunk(room_id).await.unwrap();
468
469 assert_eq!(chunk_identifier_generator.current(), 2);
470
471 let linked_chunk = lazy_loader::from_last_chunk::<DEFAULT_CHUNK_CAPACITY, _, _>(
472 last_chunk,
473 chunk_identifier_generator,
474 )
475 .unwrap() .unwrap(); let mut rchunks = linked_chunk.rchunks();
479
480 assert_matches!(rchunks.next(), Some(chunk) => {
482 assert_eq!(chunk.identifier(), 2);
483 assert_eq!(chunk.lazy_previous(), Some(CId::new(1)));
484
485 assert_matches!(chunk.content(), ChunkContent::Items(events) => {
486 assert_eq!(events.len(), 3);
487 check_test_event(&events[0], "c");
488 check_test_event(&events[1], "d");
489 check_test_event(&events[2], "e");
490 });
491 });
492
493 assert!(rchunks.next().is_none());
494
495 linked_chunk
496 };
497
498 {
500 let first_chunk = linked_chunk.chunks().next().unwrap().identifier();
501 let previous_chunk =
502 self.load_previous_chunk(room_id, first_chunk).await.unwrap().unwrap();
503
504 let _ = lazy_loader::insert_new_first_chunk(&mut linked_chunk, previous_chunk).unwrap();
505
506 let mut rchunks = linked_chunk.rchunks();
507
508 assert_matches!(rchunks.next(), Some(chunk) => {
510 assert_eq!(chunk.identifier(), 2);
511 assert!(chunk.lazy_previous().is_none());
512
513 assert_matches!(chunk.content(), ChunkContent::Items(events) => {
515 assert_eq!(events.len(), 3);
516 check_test_event(&events[0], "c");
517 check_test_event(&events[1], "d");
518 check_test_event(&events[2], "e");
519 });
520 });
521
522 assert_matches!(rchunks.next(), Some(chunk) => {
524 assert_eq!(chunk.identifier(), 1);
525 assert_eq!(chunk.lazy_previous(), Some(CId::new(0)));
526
527 assert_matches!(chunk.content(), ChunkContent::Gap(gap) => {
528 assert_eq!(gap.prev_token, "morbier");
529 });
530 });
531
532 assert!(rchunks.next().is_none());
533 }
534
535 {
537 let first_chunk = linked_chunk.chunks().next().unwrap().identifier();
538 let previous_chunk =
539 self.load_previous_chunk(room_id, first_chunk).await.unwrap().unwrap();
540
541 let _ = lazy_loader::insert_new_first_chunk(&mut linked_chunk, previous_chunk).unwrap();
542
543 let mut rchunks = linked_chunk.rchunks();
544
545 assert_matches!(rchunks.next(), Some(chunk) => {
547 assert_eq!(chunk.identifier(), 2);
548 assert!(chunk.lazy_previous().is_none());
549
550 assert_matches!(chunk.content(), ChunkContent::Items(events) => {
552 assert_eq!(events.len(), 3);
553 check_test_event(&events[0], "c");
554 check_test_event(&events[1], "d");
555 check_test_event(&events[2], "e");
556 });
557 });
558
559 assert_matches!(rchunks.next(), Some(chunk) => {
561 assert_eq!(chunk.identifier(), 1);
562 assert!(chunk.lazy_previous().is_none());
563
564 assert_matches!(chunk.content(), ChunkContent::Gap(gap) => {
566 assert_eq!(gap.prev_token, "morbier");
567 });
568 });
569
570 assert_matches!(rchunks.next(), Some(chunk) => {
572 assert_eq!(chunk.identifier(), 0);
573 assert!(chunk.lazy_previous().is_none());
574
575 assert_matches!(chunk.content(), ChunkContent::Items(events) => {
576 assert_eq!(events.len(), 2);
577 check_test_event(&events[0], "a");
578 check_test_event(&events[1], "b");
579 });
580 });
581
582 assert!(rchunks.next().is_none());
583 }
584
585 {
587 let first_chunk = linked_chunk.chunks().next().unwrap().identifier();
588 let previous_chunk = self.load_previous_chunk(room_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(&DEFAULT_TEST_ROOM_ID).await.unwrap(),
641 )
642 .unwrap();
643 assert!(linked_chunk.is_none());
644 }
645
646 async fn test_clear_all_rooms_chunks(&self) {
647 let r0 = room_id!("!r0:matrix.org");
648 let r1 = room_id!("!r1:matrix.org");
649
650 self.handle_linked_chunk_updates(
652 r0,
653 vec![
654 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
656 Update::PushItems {
658 at: Position::new(CId::new(0), 0),
659 items: vec![make_test_event(r0, "hello"), make_test_event(r0, "world")],
660 },
661 ],
662 )
663 .await
664 .unwrap();
665
666 self.handle_linked_chunk_updates(
668 r1,
669 vec![
670 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
672 Update::NewGapChunk {
674 previous: Some(CId::new(0)),
675 new: CId::new(1),
676 next: None,
677 gap: Gap { prev_token: "bleu d'auvergne".to_owned() },
678 },
679 Update::NewItemsChunk { previous: Some(CId::new(1)), new: CId::new(2), next: None },
681 Update::PushItems {
683 at: Position::new(CId::new(2), 0),
684 items: vec![make_test_event(r0, "yummy")],
685 },
686 ],
687 )
688 .await
689 .unwrap();
690
691 assert!(lazy_loader::from_all_chunks::<3, _, _>(self.load_all_chunks(r0).await.unwrap())
693 .unwrap()
694 .is_some());
695 assert!(lazy_loader::from_all_chunks::<3, _, _>(self.load_all_chunks(r1).await.unwrap())
696 .unwrap()
697 .is_some());
698
699 self.clear_all_rooms_chunks().await.unwrap();
701
702 assert!(lazy_loader::from_all_chunks::<3, _, _>(self.load_all_chunks(r0).await.unwrap())
704 .unwrap()
705 .is_none());
706 assert!(lazy_loader::from_all_chunks::<3, _, _>(self.load_all_chunks(r1).await.unwrap())
707 .unwrap()
708 .is_none());
709 }
710
711 async fn test_remove_room(&self) {
712 let r0 = room_id!("!r0:matrix.org");
713 let r1 = room_id!("!r1:matrix.org");
714
715 self.handle_linked_chunk_updates(
717 r0,
718 vec![
719 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
721 Update::PushItems {
723 at: Position::new(CId::new(0), 0),
724 items: vec![make_test_event(r0, "hello"), make_test_event(r0, "world")],
725 },
726 ],
727 )
728 .await
729 .unwrap();
730
731 self.handle_linked_chunk_updates(
733 r1,
734 vec![
735 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
737 Update::PushItems {
739 at: Position::new(CId::new(0), 0),
740 items: vec![make_test_event(r0, "yummy")],
741 },
742 ],
743 )
744 .await
745 .unwrap();
746
747 self.remove_room(r0).await.unwrap();
749
750 let r0_linked_chunk = self.load_all_chunks(r0).await.unwrap();
752 assert!(r0_linked_chunk.is_empty());
753
754 let r1_linked_chunk = self.load_all_chunks(r1).await.unwrap();
756 assert!(!r1_linked_chunk.is_empty());
757 }
758
759 async fn test_filter_duplicated_events(&self) {
760 let room_id = room_id!("!r0:matrix.org");
761 let another_room_id = room_id!("!r1:matrix.org");
762 let event = |msg: &str| make_test_event(room_id, msg);
763
764 let event_comte = event("comté");
765 let event_brigand = event("brigand du jorat");
766 let event_raclette = event("raclette");
767 let event_morbier = event("morbier");
768 let event_gruyere = event("gruyère");
769 let event_tome = event("tome");
770 let event_mont_dor = event("mont d'or");
771
772 self.handle_linked_chunk_updates(
773 room_id,
774 vec![
775 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
776 Update::PushItems {
777 at: Position::new(CId::new(0), 0),
778 items: vec![event_comte.clone(), event_brigand.clone()],
779 },
780 Update::NewGapChunk {
781 previous: Some(CId::new(0)),
782 new: CId::new(1),
783 next: None,
784 gap: Gap { prev_token: "brillat-savarin".to_owned() },
785 },
786 Update::NewItemsChunk { previous: Some(CId::new(1)), new: CId::new(2), next: None },
787 Update::PushItems {
788 at: Position::new(CId::new(2), 0),
789 items: vec![event_morbier.clone(), event_mont_dor.clone()],
790 },
791 ],
792 )
793 .await
794 .unwrap();
795
796 self.handle_linked_chunk_updates(
799 another_room_id,
800 vec![
801 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
802 Update::PushItems {
803 at: Position::new(CId::new(0), 0),
804 items: vec![event_tome.clone()],
805 },
806 ],
807 )
808 .await
809 .unwrap();
810
811 let duplicated_events = self
812 .filter_duplicated_events(
813 room_id,
814 vec![
815 event_comte.event_id().unwrap().to_owned(),
816 event_raclette.event_id().unwrap().to_owned(),
817 event_morbier.event_id().unwrap().to_owned(),
818 event_gruyere.event_id().unwrap().to_owned(),
819 event_tome.event_id().unwrap().to_owned(),
820 event_mont_dor.event_id().unwrap().to_owned(),
821 ],
822 )
823 .await
824 .unwrap();
825
826 assert_eq!(duplicated_events.len(), 3);
827 assert_eq!(
828 duplicated_events[0],
829 (event_comte.event_id().unwrap(), Position::new(CId::new(0), 0))
830 );
831 assert_eq!(
832 duplicated_events[1],
833 (event_morbier.event_id().unwrap(), Position::new(CId::new(2), 0))
834 );
835 assert_eq!(
836 duplicated_events[2],
837 (event_mont_dor.event_id().unwrap(), Position::new(CId::new(2), 1))
838 );
839 }
840
841 async fn test_find_event(&self) {
842 let room_id = room_id!("!r0:matrix.org");
843 let another_room_id = room_id!("!r1:matrix.org");
844 let event = |msg: &str| make_test_event(room_id, msg);
845
846 let event_comte = event("comté");
847 let event_gruyere = event("gruyère");
848
849 self.handle_linked_chunk_updates(
851 room_id,
852 vec![
853 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
854 Update::PushItems {
855 at: Position::new(CId::new(0), 0),
856 items: vec![event_comte.clone()],
857 },
858 ],
859 )
860 .await
861 .unwrap();
862
863 self.handle_linked_chunk_updates(
865 another_room_id,
866 vec![
867 Update::NewItemsChunk { previous: None, new: CId::new(0), next: None },
868 Update::PushItems {
869 at: Position::new(CId::new(0), 0),
870 items: vec![event_gruyere.clone()],
871 },
872 ],
873 )
874 .await
875 .unwrap();
876
877 let event = self
879 .find_event(room_id, event_comte.event_id().unwrap().as_ref())
880 .await
881 .expect("failed to query for finding an event")
882 .expect("failed to find an event");
883
884 assert_eq!(event.event_id(), event_comte.event_id());
885
886 assert!(self
888 .find_event(room_id, event_gruyere.event_id().unwrap().as_ref())
889 .await
890 .expect("failed to query for finding an event")
891 .is_none());
892
893 self.clear_all_rooms_chunks().await.expect("failed to clear all rooms chunks");
895 assert!(self
896 .find_event(room_id, event_comte.event_id().unwrap().as_ref())
897 .await
898 .expect("failed to query for finding an event")
899 .is_none());
900 }
901
902 async fn test_find_event_relations(&self) {
903 let room_id = room_id!("!r0:matrix.org");
904 let another_room_id = room_id!("!r1:matrix.org");
905
906 let f = EventFactory::new().room(room_id).sender(*ALICE);
907
908 let eid1 = event_id!("$event1:matrix.org");
910 let e1 = f.text_msg("comter").event_id(eid1).into_event();
911
912 let edit_eid1 = event_id!("$edit_event1:matrix.org");
913 let edit_e1 = f
914 .text_msg("* comté")
915 .event_id(edit_eid1)
916 .edit(eid1, RoomMessageEventContentWithoutRelation::text_plain("comté"))
917 .into_event();
918
919 let reaction_eid1 = event_id!("$reaction_event1:matrix.org");
920 let reaction_e1 = f.reaction(eid1, "👍").event_id(reaction_eid1).into_event();
921
922 let eid2 = event_id!("$event2:matrix.org");
923 let e2 = f.text_msg("galette saucisse").event_id(eid2).into_event();
924
925 let f = f.room(another_room_id);
927
928 let eid3 = event_id!("$event3:matrix.org");
929 let e3 = f.text_msg("gruyère").event_id(eid3).into_event();
930
931 let reaction_eid3 = event_id!("$reaction_event3:matrix.org");
932 let reaction_e3 = f.reaction(eid3, "👍").event_id(reaction_eid3).into_event();
933
934 self.save_event(room_id, e1).await.unwrap();
936 self.save_event(room_id, edit_e1).await.unwrap();
937 self.save_event(room_id, reaction_e1).await.unwrap();
938 self.save_event(room_id, e2).await.unwrap();
939 self.save_event(another_room_id, e3).await.unwrap();
940 self.save_event(another_room_id, reaction_e3).await.unwrap();
941
942 let relations = self.find_event_relations(room_id, eid1, None).await.unwrap();
944 assert_eq!(relations.len(), 2);
945 assert!(relations.iter().any(|r| r.event_id().as_deref() == Some(edit_eid1)));
946 assert!(relations.iter().any(|r| r.event_id().as_deref() == Some(reaction_eid1)));
947
948 let relations = self
950 .find_event_relations(room_id, eid1, Some(&[RelationType::Replacement]))
951 .await
952 .unwrap();
953 assert_eq!(relations.len(), 1);
954 assert_eq!(relations[0].event_id().as_deref(), Some(edit_eid1));
955
956 let relations = self
957 .find_event_relations(
958 room_id,
959 eid1,
960 Some(&[RelationType::Replacement, RelationType::Annotation]),
961 )
962 .await
963 .unwrap();
964 assert_eq!(relations.len(), 2);
965 assert!(relations.iter().any(|r| r.event_id().as_deref() == Some(edit_eid1)));
966 assert!(relations.iter().any(|r| r.event_id().as_deref() == Some(reaction_eid1)));
967
968 let relations = self
970 .find_event_relations(another_room_id, eid1, Some(&[RelationType::Replacement]))
971 .await
972 .unwrap();
973 assert!(relations.is_empty());
974 }
975
976 async fn test_save_event(&self) {
977 let room_id = room_id!("!r0:matrix.org");
978 let another_room_id = room_id!("!r1:matrix.org");
979
980 let event = |msg: &str| make_test_event(room_id, msg);
981 let event_comte = event("comté");
982 let event_gruyere = event("gruyère");
983
984 self.save_event(room_id, event_comte.clone()).await.unwrap();
986
987 self.save_event(another_room_id, event_gruyere.clone()).await.unwrap();
989
990 let event = self
992 .find_event(room_id, event_comte.event_id().unwrap().as_ref())
993 .await
994 .expect("failed to query for finding an event")
995 .expect("failed to find an event");
996 assert_eq!(event.event_id(), event_comte.event_id());
997
998 let event = self
999 .find_event(another_room_id, event_gruyere.event_id().unwrap().as_ref())
1000 .await
1001 .expect("failed to query for finding an event")
1002 .expect("failed to find an event");
1003 assert_eq!(event.event_id(), event_gruyere.event_id());
1004
1005 assert!(self
1007 .find_event(another_room_id, event_comte.event_id().unwrap().as_ref())
1008 .await
1009 .expect("failed to query for finding an event")
1010 .is_none());
1011 assert!(self
1012 .find_event(room_id, event_gruyere.event_id().unwrap().as_ref())
1013 .await
1014 .expect("failed to query for finding an event")
1015 .is_none());
1016 }
1017}
1018
1019#[allow(unused_macros, unused_extern_crates)]
1047#[macro_export]
1048macro_rules! event_cache_store_integration_tests {
1049 () => {
1050 mod event_cache_store_integration_tests {
1051 use matrix_sdk_test::async_test;
1052 use $crate::event_cache::store::{
1053 EventCacheStoreIntegrationTests, IntoEventCacheStore,
1054 };
1055
1056 use super::get_event_cache_store;
1057
1058 #[async_test]
1059 async fn test_media_content() {
1060 let event_cache_store =
1061 get_event_cache_store().await.unwrap().into_event_cache_store();
1062 event_cache_store.test_media_content().await;
1063 }
1064
1065 #[async_test]
1066 async fn test_replace_media_key() {
1067 let event_cache_store =
1068 get_event_cache_store().await.unwrap().into_event_cache_store();
1069 event_cache_store.test_replace_media_key().await;
1070 }
1071
1072 #[async_test]
1073 async fn test_handle_updates_and_rebuild_linked_chunk() {
1074 let event_cache_store =
1075 get_event_cache_store().await.unwrap().into_event_cache_store();
1076 event_cache_store.test_handle_updates_and_rebuild_linked_chunk().await;
1077 }
1078
1079 #[async_test]
1080 async fn test_linked_chunk_incremental_loading() {
1081 let event_cache_store =
1082 get_event_cache_store().await.unwrap().into_event_cache_store();
1083 event_cache_store.test_linked_chunk_incremental_loading().await;
1084 }
1085
1086 #[async_test]
1087 async fn test_rebuild_empty_linked_chunk() {
1088 let event_cache_store =
1089 get_event_cache_store().await.unwrap().into_event_cache_store();
1090 event_cache_store.test_rebuild_empty_linked_chunk().await;
1091 }
1092
1093 #[async_test]
1094 async fn test_clear_all_rooms_chunks() {
1095 let event_cache_store =
1096 get_event_cache_store().await.unwrap().into_event_cache_store();
1097 event_cache_store.test_clear_all_rooms_chunks().await;
1098 }
1099
1100 #[async_test]
1101 async fn test_remove_room() {
1102 let event_cache_store =
1103 get_event_cache_store().await.unwrap().into_event_cache_store();
1104 event_cache_store.test_remove_room().await;
1105 }
1106
1107 #[async_test]
1108 async fn test_filter_duplicated_events() {
1109 let event_cache_store =
1110 get_event_cache_store().await.unwrap().into_event_cache_store();
1111 event_cache_store.test_filter_duplicated_events().await;
1112 }
1113
1114 #[async_test]
1115 async fn test_find_event() {
1116 let event_cache_store =
1117 get_event_cache_store().await.unwrap().into_event_cache_store();
1118 event_cache_store.test_find_event().await;
1119 }
1120
1121 #[async_test]
1122 async fn test_find_event_relations() {
1123 let event_cache_store =
1124 get_event_cache_store().await.unwrap().into_event_cache_store();
1125 event_cache_store.test_find_event_relations().await;
1126 }
1127
1128 #[async_test]
1129 async fn test_save_event() {
1130 let event_cache_store =
1131 get_event_cache_store().await.unwrap().into_event_cache_store();
1132 event_cache_store.test_save_event().await;
1133 }
1134 }
1135 };
1136}
1137
1138#[allow(unused_macros)]
1141#[macro_export]
1142macro_rules! event_cache_store_integration_tests_time {
1143 () => {
1144 #[cfg(not(target_arch = "wasm32"))]
1145 mod event_cache_store_integration_tests_time {
1146 use std::time::Duration;
1147
1148 use matrix_sdk_test::async_test;
1149 use $crate::event_cache::store::IntoEventCacheStore;
1150
1151 use super::get_event_cache_store;
1152
1153 #[async_test]
1154 async fn test_lease_locks() {
1155 let store = get_event_cache_store().await.unwrap().into_event_cache_store();
1156
1157 let acquired0 = store.try_take_leased_lock(0, "key", "alice").await.unwrap();
1158 assert!(acquired0);
1159
1160 let acquired2 = store.try_take_leased_lock(300, "key", "alice").await.unwrap();
1162 assert!(acquired2);
1163
1164 let acquired3 = store.try_take_leased_lock(300, "key", "alice").await.unwrap();
1166 assert!(acquired3);
1167
1168 let acquired4 = store.try_take_leased_lock(300, "key", "bob").await.unwrap();
1170 assert!(!acquired4);
1171
1172 let acquired5 = store.try_take_leased_lock(300, "key", "bob").await.unwrap();
1174 assert!(!acquired5);
1175
1176 tokio::time::sleep(Duration::from_millis(50)).await;
1178
1179 let acquired55 = store.try_take_leased_lock(300, "key", "bob").await.unwrap();
1181 assert!(!acquired55);
1182
1183 tokio::time::sleep(Duration::from_millis(250)).await;
1185
1186 let acquired6 = store.try_take_leased_lock(0, "key", "bob").await.unwrap();
1188 assert!(acquired6);
1189
1190 tokio::time::sleep(Duration::from_millis(1)).await;
1191
1192 let acquired7 = store.try_take_leased_lock(0, "key", "alice").await.unwrap();
1194 assert!(acquired7);
1195
1196 tokio::time::sleep(Duration::from_millis(1)).await;
1197
1198 let acquired8 = store.try_take_leased_lock(300, "key", "bob").await.unwrap();
1200 assert!(acquired8);
1201
1202 let acquired9 = store.try_take_leased_lock(300, "key", "alice").await.unwrap();
1204 assert!(!acquired9);
1205
1206 let acquired10 = store.try_take_leased_lock(300, "key", "bob").await.unwrap();
1208 assert!(acquired10);
1209 }
1210 }
1211 };
1212}