matrix_sdk_crypto/store/
integration_tests.rs

1/// A macro which will run the CryptoStore integration test suite.
2///
3/// You need to provide a `async fn get_store() -> StoreResult<impl StateStore>`
4/// providing a fresh store on the same level you invoke the macro.
5///
6/// ## Usage Example:
7/// ```no_run
8/// # use matrix_sdk_crypto::store::{
9/// #    MemoryStore as MyCryptoStore,
10/// # };
11///
12/// #[cfg(test)]
13/// mod tests {
14///     use super::MyCryptoStore;
15///
16///     async fn get_store(
17///         name: &str,
18///         passphrase: Option<&str>,
19///         clear_data: bool,
20///     ) -> MyCryptoStore {
21///         let store = MyCryptoStore::new();
22///         if clear_data {
23///             store.clear();
24///         }
25///         store
26///     }
27///
28///     cryptostore_integration_tests!();
29/// }
30/// ```
31#[allow(unused_macros)]
32#[macro_export]
33macro_rules! cryptostore_integration_tests {
34    () => {
35        mod cryptostore_integration_tests {
36            use std::collections::{BTreeMap, HashMap};
37            use std::time::Duration;
38
39            use assert_matches::assert_matches;
40            use matrix_sdk_test::async_test;
41            use ruma::{
42                device_id, events::secret::request::SecretName, room_id, serde::Raw,
43                to_device::DeviceIdOrAllDevices, user_id, DeviceId, RoomId, TransactionId, UserId,
44            };
45            use serde_json::value::to_raw_value;
46            use serde_json::json;
47            use matrix_sdk_common::deserialized_responses::WithheldCode;
48            use $crate::{
49                olm::{
50                    Account, Curve25519PublicKey, InboundGroupSession, OlmMessageHash,
51                    PrivateCrossSigningIdentity, SenderData, SenderDataType, Session
52                },
53                store::{
54                    BackupDecryptionKey, Changes, CryptoStore, DehydratedDeviceKey, DeviceChanges, GossipRequest,
55                    IdentityChanges, PendingChanges, RoomSettings,
56                },
57                testing::{get_device, get_other_identity, get_own_identity},
58                types::{
59                    events::{
60                        dummy::DummyEventContent,
61                        olm_v1::{DecryptedSecretSendEvent, OlmV1Keys},
62                        room_key_request::MegolmV1AesSha2Content,
63                        room_key_withheld::{
64                            CommonWithheldCodeContent, MegolmV1AesSha2WithheldContent,
65                            RoomKeyWithheldContent,
66                        },
67                        secret_send::SecretSendContent,
68                        ToDeviceEvent,
69                    },
70                    requests::ToDeviceRequest,
71                    DeviceKeys,
72                    EventEncryptionAlgorithm,
73                },
74                vodozemac::megolm::{GroupSession, SessionConfig}, DeviceData, GossippedSecret, LocalTrust,  SecretInfo,
75                TrackedUser,
76            };
77
78            use super::get_store;
79
80            fn alice_id() -> &'static UserId {
81                user_id!("@alice:example.org")
82            }
83
84            fn alice_device_id() -> &'static DeviceId {
85                device_id!("ALICEDEVICE")
86            }
87
88            fn bob_id() -> &'static UserId {
89                user_id!("@bob:example.org")
90            }
91
92            fn bob_device_id() -> &'static DeviceId {
93                device_id!("BOBDEVICE")
94            }
95
96            pub async fn get_loaded_store(name: &str) -> (Account, impl CryptoStore) {
97                let store = get_store(name, None, true).await;
98                let account = get_account();
99
100                store.save_pending_changes(PendingChanges { account: Some(account.deep_clone()), }).await.expect("Can't save account");
101
102                (account, store)
103            }
104
105            fn get_account() -> Account {
106                Account::with_device_id(alice_id(), alice_device_id())
107            }
108
109            pub(crate) async fn get_account_and_session() -> (Account, Session) {
110                let alice = Account::with_device_id(alice_id(), alice_device_id());
111                let mut bob = Account::with_device_id(bob_id(), bob_device_id());
112
113                bob.generate_one_time_keys(1);
114                let one_time_key = *bob.one_time_keys().values().next().unwrap();
115                let sender_key = bob.identity_keys().curve25519;
116                let session = alice.create_outbound_session_helper(
117                    Default::default(),
118                    sender_key,
119                    one_time_key,
120                    false,
121                    alice.device_keys(),
122                );
123
124                (alice, session)
125            }
126
127            #[async_test]
128            async fn test_save_account_via_generic_save() {
129                let store = get_store("save_account_via_generic", None, true).await;
130                assert!(store.get_static_account().is_none());
131                assert!(store.load_account().await.unwrap().is_none());
132                let account = get_account();
133
134                store
135                    .save_pending_changes(PendingChanges { account: Some(account) })
136                    .await
137                    .expect("Can't save account");
138                assert!(store.get_static_account().is_some());
139            }
140
141            #[async_test]
142            async fn test_save_account() {
143                let store = get_store("save_account", None, true).await;
144                assert!(store.get_static_account().is_none());
145                assert!(store.load_account().await.unwrap().is_none());
146                let account = get_account();
147
148                store
149                    .save_pending_changes(PendingChanges { account: Some(account) })
150                    .await
151                    .expect("Can't save account");
152                assert!(store.get_static_account().is_some());
153            }
154
155            #[async_test]
156            async fn test_load_account() {
157                let store = get_store("load_account", None, true).await;
158                let account = get_account();
159
160                store
161                    .save_pending_changes(PendingChanges { account: Some(account.deep_clone()) })
162                    .await
163                    .expect("Can't save account");
164
165                let loaded_account = store.load_account().await.expect("Can't load account");
166                let loaded_account = loaded_account.unwrap();
167
168                assert_eq!(account, loaded_account);
169            }
170
171            #[async_test]
172            async fn test_load_account_with_passphrase() {
173                let passphrase = Some("secret_passphrase");
174                let store = get_store("load_account_with_passphrase", passphrase, true).await;
175                let account = get_account();
176
177                store
178                    .save_pending_changes(PendingChanges { account: Some(account.deep_clone()) })
179                    .await
180                    .expect("Can't save account");
181
182                let loaded_account = store.load_account().await.expect("Can't load account");
183                let loaded_account = loaded_account.unwrap();
184
185                assert_eq!(account, loaded_account);
186            }
187
188            #[async_test]
189            async fn test_save_and_share_account() {
190                let store = get_store("save_and_share_account", None, true).await;
191                let mut account = get_account();
192
193                store
194                    .save_pending_changes(PendingChanges { account: Some(account.deep_clone()) })
195                    .await
196                    .expect("Can't save account");
197
198                account.mark_as_shared();
199                account.update_uploaded_key_count(50);
200
201                store
202                    .save_pending_changes(PendingChanges { account: Some(account.deep_clone()) })
203                    .await
204                    .expect("Can't save account");
205
206                let loaded_account = store.load_account().await.expect("Can't load account");
207                let loaded_account = loaded_account.unwrap();
208
209                assert_eq!(account, loaded_account);
210                assert_eq!(account.uploaded_key_count(), loaded_account.uploaded_key_count());
211            }
212
213            #[async_test]
214            async fn test_load_sessions() {
215                let store = get_store("load_sessions", None, true).await;
216                let (account, session) = get_account_and_session().await;
217                store
218                    .save_pending_changes(PendingChanges { account: Some(account.deep_clone()) })
219                    .await
220                    .expect("Can't save account");
221
222                let changes = Changes {
223                    sessions: vec![session.clone()],
224                    devices: DeviceChanges { new: vec![DeviceData::from_account(&account)], ..Default::default() },
225                    ..Default::default()
226                };
227
228                store.save_changes(changes).await.unwrap();
229
230                let sessions = store
231                    .get_sessions(&session.sender_key.to_base64())
232                    .await
233                    .expect("Can't load sessions")
234                    .unwrap();
235                let loaded_session = sessions.get(0).cloned().expect("We should find the session in the store.");
236
237                assert_eq!(&session, &loaded_session, "The loaded session should be the same one we put into the store.");
238            }
239
240            #[async_test]
241            async fn test_add_and_save_session() {
242                let store_name = "add_and_save_session";
243
244                // Given we created a session and saved it in the store
245                let (session_id, account, sender_key) = {
246                    let store = get_store(store_name, None, true).await;
247                    let (account, session) = get_account_and_session().await;
248                    let sender_key = session.sender_key.to_base64();
249                    let session_id = session.session_id().to_owned();
250
251                    store
252                        .save_pending_changes(PendingChanges {
253                            account: Some(account.deep_clone()),
254                        })
255                        .await
256                        .expect("Can't save account");
257                    store
258                        .save_changes(Changes {
259                            devices: DeviceChanges {
260                                new: vec![DeviceData::from_account(&account)],
261                                ..Default::default()
262                            },
263                            ..Default::default()
264                        })
265                        .await
266                        .unwrap();
267
268                    let changes = Changes { sessions: vec![session.clone()], ..Default::default() };
269                    store.save_changes(changes).await.unwrap();
270
271                    let sessions = store.get_sessions(&sender_key).await.unwrap().unwrap();
272                    let session = &sessions[0];
273
274                    assert_eq!(session_id, session.session_id());
275
276                    (session_id, account, sender_key)
277                };
278
279                // When we reload the store
280                let store = get_store(store_name, None, false).await;
281
282                // Then the same account and session info was reloaded
283                let loaded_account = store.load_account().await.unwrap().unwrap();
284                assert_eq!(account, loaded_account);
285
286                let sessions = store.get_sessions(&sender_key).await.unwrap().unwrap();
287                let session = &sessions[0];
288
289                assert_eq!(session_id, session.session_id());
290            }
291
292            #[async_test]
293            async fn test_load_outbound_group_session() {
294                let dir = "load_outbound_group_session";
295                let room_id = room_id!("!test:localhost");
296
297                // Given we saved an outbound group session
298                {
299                    let (account, store) = get_loaded_store(dir.clone()).await;
300                    assert!(
301                        store.get_outbound_group_session(&room_id).await.unwrap().is_none(),
302                        "Initially there should be no outbound group session"
303                    );
304
305                    let (session, _) =
306                        account.create_group_session_pair_with_defaults(&room_id).await;
307
308                    let user_id = user_id!("@example:localhost");
309                    let request = ToDeviceRequest::new(
310                        user_id,
311                        DeviceIdOrAllDevices::AllDevices,
312                        "m.dummy",
313                        Raw::from_json(to_raw_value(&DummyEventContent::new()).unwrap()),
314                    );
315
316                    session.add_request(TransactionId::new(), request.into(), Default::default());
317
318                    let changes = Changes {
319                        outbound_group_sessions: vec![session.clone()],
320                        ..Default::default()
321                    };
322
323                    store.save_changes(changes).await.expect("Can't save group session");
324                    assert!(
325                        store.get_outbound_group_session(&room_id).await.unwrap().is_some(),
326                        "Sanity: after we've saved one, there should be an outbound_group_session"
327                    );
328                }
329
330                // When we reload the account
331                let store = get_store(dir, None, false).await;
332                store.load_account().await.unwrap();
333
334                // Then the saved session is restored
335                assert!(
336                    store.get_outbound_group_session(&room_id).await.unwrap().is_some(),
337                    "The outbound_group_session should have been loaded"
338                );
339            }
340
341            /// Test that we can import an inbound group session via [`CryptoStore::save_changes`]
342            #[async_test]
343            async fn test_save_changes_save_inbound_group_session() {
344                let (account, store) = get_loaded_store("save_inbound_group_session").await;
345
346                let room_id = &room_id!("!test:localhost");
347                let (_, session) = account.create_group_session_pair_with_defaults(room_id).await;
348
349                let changes =
350                    Changes { inbound_group_sessions: vec![session], ..Default::default() };
351
352                store.save_changes(changes).await.expect("Can't save group session");
353            }
354
355            /// Test that we can import a backed-up group session via
356            /// [`CryptoStore::save_inbound_group_sessions`]
357            #[async_test]
358            async fn test_save_inbound_group_session_from_backup() {
359                let (account, store) =
360                    get_loaded_store("save_inbound_group_session_from_backup").await;
361
362                let room_id = &room_id!("!test:localhost");
363                let (_, session) = account.create_group_session_pair_with_defaults(room_id).await;
364
365                session.mark_as_backed_up();
366                store
367                    .save_inbound_group_sessions(vec![session.clone()], Some(&"bkpver1"))
368                    .await
369                    .expect("could not save sessions");
370
371                let loaded_session = store
372                    .get_inbound_group_session(&session.room_id, session.session_id())
373                    .await
374                    .expect("error when loading session")
375                    .expect("session not found in store");
376                assert_eq!(session, loaded_session);
377                assert_eq!(store.get_inbound_group_sessions().await.unwrap().len(), 1);
378                assert_eq!(store.inbound_group_session_counts(None).await.unwrap().total, 1);
379
380                // It should *not* be returned by a request for backup for the same backup version
381                let to_back_up = store.inbound_group_sessions_for_backup("bkpver1", 1).await.unwrap();
382                assert_eq!(to_back_up.len(), 0, "backup was returned by backup query");
383                assert_eq!(
384                    store.inbound_group_session_counts(Some(&"bkpver1")).await.unwrap().backed_up, 1,
385                    "backed_up count",
386                );
387            }
388
389            /// Test that the behaviour of a key imported from an *old* backup is correct
390            ///
391            /// This currently only works on the MemoryStore, so is ignored. The other stores
392            /// are waiting for more work on https://github.com/element-hq/element-web/issues/26892.
393            #[ignore]
394            #[async_test]
395            async fn test_save_inbound_group_session_from_old_backup() {
396                let (account, store) =
397                    get_loaded_store("save_inbound_group_session_from_old_backup").await;
398
399                let room_id = &room_id!("!test:localhost");
400                let (_, session) = account.create_group_session_pair_with_defaults(room_id).await;
401
402                session.mark_as_backed_up();
403                store
404                    .save_inbound_group_sessions(vec![session.clone()], Some(&"bkpver1"))
405                    .await
406                    .expect("could not save sessions");
407
408                // The session should be returned by a request for backup from a different backup version.
409                let to_back_up = store.inbound_group_sessions_for_backup("bkpver2", 1).await.unwrap();
410                assert_eq!(to_back_up, vec![session]);
411                assert_eq!(
412                    store.inbound_group_session_counts(Some(&"bkpver2")).await.unwrap().backed_up, 0,
413                    "backed_up count for backup version 2",
414                );
415            }
416
417            /// Test that we can import a not-backed-up group session via
418            /// [`CryptoStore::save_inbound_group_sessions`]
419            #[async_test]
420            async fn test_save_inbound_group_session_from_import() {
421                let (account, store) =
422                    get_loaded_store("save_inbound_group_session_from_import").await;
423
424                let room_id = &room_id!("!test:localhost");
425                let (_, session) = account.create_group_session_pair_with_defaults(room_id).await;
426
427                store
428                    .save_inbound_group_sessions(vec![session.clone()], None)
429                    .await
430                    .expect("could not save sessions");
431
432                let loaded_session = store
433                    .get_inbound_group_session(&session.room_id, session.session_id())
434                    .await
435                    .expect("error when loading session")
436                    .expect("session not found in store");
437                assert_eq!(session, loaded_session);
438                assert_eq!(store.get_inbound_group_sessions().await.unwrap().len(), 1);
439                assert_eq!(store.inbound_group_session_counts(None).await.unwrap().total, 1);
440                assert_eq!(store.inbound_group_session_counts(None).await.unwrap().backed_up, 0);
441
442                // It should be returned by a request for backup
443                let to_back_up = store.inbound_group_sessions_for_backup("bkpver1", 1).await.unwrap();
444                assert_eq!(to_back_up, vec![session]);
445            }
446
447            #[async_test]
448            async fn test_mark_inbound_group_sessions_as_backed_up() {
449                // Given a store exists with multiple unbacked-up sessions
450                let (account, store) =
451                    get_loaded_store("mark_inbound_group_sessions_as_backed_up").await;
452                let room_id = &room_id!("!test:localhost");
453                let mut sessions: Vec<InboundGroupSession> = Vec::with_capacity(10);
454                for _i in 0..10 {
455                    sessions.push(account.create_group_session_pair_with_defaults(room_id).await.1);
456                }
457                let changes = Changes { inbound_group_sessions: sessions.clone(), ..Default::default() };
458                store.save_changes(changes).await.expect("Can't save group session");
459                assert_eq!(store.inbound_group_sessions_for_backup("bkpver", 100).await.unwrap().len(), 10);
460
461                // When I mark some as backed up
462                store.mark_inbound_group_sessions_as_backed_up("bkpver", &[
463                    session_info(&sessions[1]),
464                    session_info(&sessions[3]),
465                    session_info(&sessions[5]),
466                    session_info(&sessions[7]),
467                    session_info(&sessions[9]),
468                ]).await.expect("Failed to mark sessions as backed up");
469
470                // And ask which still need backing up
471                let to_back_up = store.inbound_group_sessions_for_backup("bkpver", 10).await.unwrap();
472                let needs_backing_up = |i: usize| to_back_up.iter().any(|s| s.session_id() == sessions[i].session_id());
473
474                // Then the sessions we said were backed up no longer need backing up
475                assert!(!needs_backing_up(1));
476                assert!(!needs_backing_up(3));
477                assert!(!needs_backing_up(5));
478                assert!(!needs_backing_up(7));
479                assert!(!needs_backing_up(9));
480
481                // And the sessions we didn't mention still need backing up
482                assert!(needs_backing_up(0));
483                assert!(needs_backing_up(2));
484                assert!(needs_backing_up(4));
485                assert!(needs_backing_up(6));
486                assert!(needs_backing_up(8));
487                assert_eq!(to_back_up.len(), 5);
488            }
489
490            #[async_test]
491            async fn test_reset_inbound_group_session_for_backup() {
492                // Given a store exists where all sessions are backed up to backup_1
493                let (account, store) =
494                    get_loaded_store("reset_inbound_group_session_for_backup").await;
495                let room_id = &room_id!("!test:localhost");
496                let mut sessions: Vec<InboundGroupSession> = Vec::with_capacity(10);
497                for _ in 0..10 {
498                    sessions.push(account.create_group_session_pair_with_defaults(room_id).await.1);
499                }
500                let changes = Changes { inbound_group_sessions: sessions.clone(), ..Default::default() };
501                store.save_changes(changes).await.expect("Can't save group session");
502                assert_eq!(store.inbound_group_sessions_for_backup("backup_1", 100).await.unwrap().len(), 10);
503                store.mark_inbound_group_sessions_as_backed_up(
504                    "backup_1",
505                    &(0..10).map(|i| session_info(&sessions[i])).collect::<Vec<_>>(),
506                ).await.expect("Failed to mark sessions as backed up");
507
508                // Sanity: none need backing up to the same backup
509                {
510                    let to_back_up_old = store.inbound_group_sessions_for_backup("backup_1", 10).await.unwrap();
511                    assert_eq!(to_back_up_old.len(), 0);
512                }
513
514                // Some stores ignore backup_version and just reset when you tell them to. Tell
515                // them here.
516                store.reset_backup_state().await.expect("reset failed");
517
518                // When we ask what needs backing up to a different backup version
519                let to_back_up = store.inbound_group_sessions_for_backup("backup_02", 10).await.unwrap();
520
521                // Then the answer is everything
522                let needs_backing_up = |i: usize| to_back_up.iter().any(|s| s.session_id() == sessions[i].session_id());
523                assert!(needs_backing_up(0));
524                assert!(needs_backing_up(1));
525                assert!(needs_backing_up(8));
526                assert!(needs_backing_up(9));
527                assert_eq!(to_back_up.len(), 10);
528            }
529
530            #[async_test]
531            async fn test_load_inbound_group_session() {
532                let dir = "load_inbound_group_session";
533                let (account, store) = get_loaded_store(dir).await;
534                assert_eq!(store.get_inbound_group_sessions().await.unwrap().len(), 0);
535
536                let room_id = &room_id!("!test:localhost");
537                let (_, session) = account.create_group_session_pair_with_defaults(room_id).await;
538
539                let export = session.export().await;
540
541                let session = InboundGroupSession::from_export(&export).unwrap();
542
543                let changes =
544                    Changes { inbound_group_sessions: vec![session.clone()], ..Default::default() };
545
546                store.save_changes(changes).await.expect("Can't save group session");
547
548                drop(store);
549
550                let store = get_store(dir, None, false).await;
551
552                store.load_account().await.unwrap();
553
554                let loaded_session = store
555                    .get_inbound_group_session(&session.room_id, session.session_id())
556                    .await
557                    .unwrap()
558                    .unwrap();
559                assert_eq!(session, loaded_session);
560                loaded_session.export().await;
561
562                assert_eq!(store.get_inbound_group_sessions().await.unwrap().len(), 1);
563                assert_eq!(store.inbound_group_session_counts(None).await.unwrap().total, 1);
564            }
565
566            #[async_test]
567            async fn test_fetch_inbound_group_sessions_for_device() {
568                // Given a store exists, containing inbound group sessions from different devices
569                let (account, store) =
570                    get_loaded_store("fetch_inbound_group_sessions_for_device").await;
571
572                let dev1 = Curve25519PublicKey::from_base64(
573                    "wjLpTLRqbqBzLs63aYaEv2Boi6cFEbbM/sSRQ2oAKk4"
574                ).unwrap();
575                let dev2 = Curve25519PublicKey::from_base64(
576                    "LTpv2DGMhggPAXO02+7f68CNEp6A40F0Yl8B094Y8gc"
577                ).unwrap();
578
579                let dev_1_unknown_a = create_session(&account, &dev1, SenderDataType::UnknownDevice).await;
580                let dev_1_unknown_b = create_session(&account, &dev1, SenderDataType::UnknownDevice).await;
581
582                let dev_1_keys_a = create_session(&account, &dev1, SenderDataType::DeviceInfo).await;
583                let dev_1_keys_b = create_session(&account, &dev1, SenderDataType::DeviceInfo).await;
584                let dev_1_keys_c = create_session(&account, &dev1, SenderDataType::DeviceInfo).await;
585                let dev_1_keys_d = create_session(&account, &dev1, SenderDataType::DeviceInfo).await;
586
587                let dev_2_unknown = create_session(
588                    &account, &dev2, SenderDataType::UnknownDevice).await;
589
590                let dev_2_keys = create_session(
591                    &account, &dev2, SenderDataType::DeviceInfo).await;
592
593                let sessions = vec![
594                    dev_1_unknown_a.clone(),
595                    dev_1_unknown_b.clone(),
596                    dev_1_keys_a.clone(),
597                    dev_1_keys_b.clone(),
598                    dev_1_keys_c.clone(),
599                    dev_1_keys_d.clone(),
600                    dev_2_unknown.clone(),
601                    dev_2_keys.clone(),
602                ];
603
604                let changes = Changes {
605                    inbound_group_sessions: sessions,
606                    ..Default::default()
607                };
608                store.save_changes(changes).await.expect("Can't save group session");
609
610                // When we fetch the list of sessions for device 1, unknown
611                let sessions_1_u = store.get_inbound_group_sessions_for_device_batch(
612                    dev1,
613                    SenderDataType::UnknownDevice,
614                    None,
615                    10
616                ).await.expect("Failed to get sessions for dev1");
617
618                // Then the expected sessions are returned
619                assert_session_lists_eq(sessions_1_u, [dev_1_unknown_a, dev_1_unknown_b], "device 1 sessions");
620
621                // And when we ask for the list of sessions for device 2, with device keys
622                let sessions_2_d = store
623                    .get_inbound_group_sessions_for_device_batch(dev2, SenderDataType::DeviceInfo, None, 10)
624                    .await
625                    .expect("Failed to get sessions for dev2");
626
627                // Then the matching session is returned
628                assert_eq!(sessions_2_d, vec![dev_2_keys], "device 2 sessions");
629
630                // And we can fetch device 1, keys in batches.
631                // We call the batch function repeatedly, to ensure it terminates correctly.
632                let mut sessions_1_k = Vec::new();
633                let mut previous_last_session_id: Option<String> = None;
634                loop {
635                    let mut sessions_1_k_batch = store.get_inbound_group_sessions_for_device_batch(
636                        dev1,
637                        SenderDataType::DeviceInfo,
638                        previous_last_session_id,
639                        2
640                    ).await.expect("Failed to get batch 1");
641
642                    // If there are no results in the batch, we have reached the end of the results.
643                    let Some(last_session) = sessions_1_k_batch.last() else {
644                        break;
645                    };
646
647                    // Check that there are exactly two results in the batch
648                    assert_eq!(sessions_1_k_batch.len(), 2);
649
650                    previous_last_session_id = Some(last_session.session_id().to_owned());
651
652                    // Modify one of the results, to check that that doesn't break iteration
653                    let mut last_session = last_session.clone();
654                    last_session.sender_data = SenderData::unknown();
655                    store.save_inbound_group_sessions(vec![last_session], None).await.unwrap();
656
657                    sessions_1_k.append(&mut sessions_1_k_batch);
658                }
659
660                assert_session_lists_eq(
661                    sessions_1_k,
662                    [dev_1_keys_a, dev_1_keys_b, dev_1_keys_c, dev_1_keys_d],
663                    "device 1 batched results"
664                );
665            }
666
667            /// Assert that two lists of sessions are the same, modulo ordering.
668            ///
669            /// There is no requirement for `get_inbound_group_sessions_for_device_batch` to
670            /// return the results in a specific order. This helper ensures that the two lists
671            /// of inbound group sessions are equivalent, without worrying about the ordering.
672            fn assert_session_lists_eq<I, J>(actual: I, expected: J, message: &str)
673                where I: IntoIterator<Item = InboundGroupSession>, J: IntoIterator<Item = InboundGroupSession>
674            {
675                let sorter = |a: &InboundGroupSession, b: &InboundGroupSession| Ord::cmp(a.session_id(), b.session_id());
676
677                let mut actual = Vec::from_iter(actual);
678                actual.sort_unstable_by(sorter);
679                let mut expected = Vec::from_iter(expected);
680                expected.sort_unstable_by(sorter);
681                assert_eq!(actual, expected, "{}", message);
682            }
683
684            #[async_test]
685            async fn test_tracked_users() {
686                let dir = "test_tracked_users";
687                let (_account, store) = get_loaded_store(dir.clone()).await;
688
689                let alice = user_id!("@alice:example.org");
690                let bob = user_id!("@bob:example.org");
691                let candy = user_id!("@candy:example.org");
692
693                let loaded = store.load_tracked_users().await.unwrap();
694                assert!(loaded.is_empty(), "Initially there are no tracked users");
695
696                let users = vec![(alice, true), (bob, false)];
697                store.save_tracked_users(&users).await.unwrap();
698
699                let check_loaded_users = |loaded: Vec<TrackedUser>| {
700                    let loaded: HashMap<_, _> =
701                        loaded.into_iter().map(|u| (u.user_id.to_owned(), u)).collect();
702
703                    let loaded_alice =
704                        loaded.get(alice).expect("Alice should be in the store as a tracked user");
705                    let loaded_bob =
706                        loaded.get(bob).expect("Bob should be in the store as as tracked user");
707
708                    assert!(!loaded.contains_key(candy), "Candy shouldn't be part of the store");
709                    assert_eq!(loaded.len(), 2, "Candy shouldn't be part of the store");
710
711                    assert!(loaded_alice.dirty, "Alice should be considered to be dirty");
712                    assert!(!loaded_bob.dirty, "Bob should not be considered to be dirty");
713                };
714
715                let loaded = store.load_tracked_users().await.unwrap();
716                check_loaded_users(loaded);
717
718                drop(store);
719
720                let name = dir.clone();let store = get_store(name, None, false).await;
721                let loaded = store.load_tracked_users().await.unwrap();
722                check_loaded_users(loaded);
723            }
724
725            #[async_test]
726            async fn test_device_saving() {
727                let dir = "device_saving";
728                let (_account, store) = get_loaded_store(dir.clone()).await;
729
730                let alice_device_1 = DeviceData::from_account(&Account::with_device_id(
731                    "@alice:localhost".try_into().unwrap(),
732                    "FIRSTDEVICE".into(),
733                ));
734
735                let alice_device_2 = DeviceData::from_account(&Account::with_device_id(
736                    "@alice:localhost".try_into().unwrap(),
737                    "SECONDDEVICE".into(),
738                ));
739
740                let json = json!({
741                    "algorithms": ["m.olm.v1.curve25519-aes-sha2", "m.megolm.v1.aes-sha2"],
742                    "user_id": "@bob:localhost",
743                    "device_id": "BOBDEVICE",
744                    "extra_property": "somevalue",
745                    "keys": {
746                        "curve25519:BOBDEVICE": "n0zs7qnaPLLf/OTL+dDLcI5kaPexbUeQ8jLQ2q6sO0E",
747                        "ed25519:BOBDEVICE": "RrKiu4+5EHRBWY6Qj6OtQGC0txpmEeanOz2irEZ/IN4",
748                    },
749                    "signatures": {
750                        "@bob:localhost": {
751                            "ed25519:BOBDEVICE": "9NjPewVHfB7Ah32mJ+CBx64mVoiQ8gbh+/2pc9WfAgut/H0Kqd/bbpgJq9Pn518szaXcGqEq0DxDP6CABBX8CQ",
752                        },
753                    },
754                });
755
756                let bob_device_1_keys: DeviceKeys = serde_json::from_value(json).unwrap();
757                let bob_device_1 = DeviceData::new(bob_device_1_keys, LocalTrust::Unset);
758
759                let changes = Changes {
760                    devices: DeviceChanges {
761                        new: vec![alice_device_1.clone(), alice_device_2.clone(), bob_device_1.clone()],
762                        ..Default::default()
763                    },
764                    ..Default::default()
765                };
766
767                store.save_changes(changes).await.unwrap();
768
769                drop(store);
770
771                let store = get_store(dir, None, false).await;
772
773                store.load_account().await.unwrap();
774
775                let loaded_device = store
776                    .get_device(alice_device_1.user_id(), alice_device_1.device_id())
777                    .await
778                    .unwrap()
779                    .unwrap();
780
781                assert_eq!(alice_device_1, loaded_device);
782
783                for algorithm in loaded_device.algorithms() {
784                    assert!(alice_device_1.algorithms().contains(algorithm));
785                }
786                assert_eq!(alice_device_1.algorithms().len(), loaded_device.algorithms().len());
787                assert_eq!(alice_device_1.keys(), loaded_device.keys());
788
789                let user_devices = store.get_user_devices(alice_device_1.user_id()).await.unwrap();
790                assert_eq!(user_devices.len(), 2);
791
792                let bob_device = store
793                    .get_device(bob_device_1.user_id(), bob_device_1.device_id())
794                    .await
795                    .unwrap();
796
797                let bob_device_json = serde_json::to_value(bob_device).unwrap();
798                assert_eq!(bob_device_json["device_keys"]["extra_property"], json!("somevalue"));
799            }
800
801            #[async_test]
802            async fn test_device_deleting() {
803                let dir = "device_deleting";
804                let (_account, store) = get_loaded_store(dir.clone()).await;
805                let device = get_device();
806
807                let changes = Changes {
808                    devices: DeviceChanges { changed: vec![device.clone()], ..Default::default() },
809                    ..Default::default()
810                };
811
812                store.save_changes(changes).await.unwrap();
813
814                let changes = Changes {
815                    devices: DeviceChanges { deleted: vec![device.clone()], ..Default::default() },
816                    ..Default::default()
817                };
818
819                store.save_changes(changes).await.unwrap();
820                drop(store);
821
822                let store = get_store(dir, None, false).await;
823
824                store.load_account().await.unwrap();
825
826                let loaded_device =
827                    store.get_device(device.user_id(), device.device_id()).await.unwrap();
828
829                assert!(loaded_device.is_none());
830            }
831
832            #[async_test]
833            async fn test_user_saving() {
834                let dir = "user_saving";
835
836                let user_id = user_id!("@example:localhost");
837                let device_id: &DeviceId = "WSKKLTJZCL".into();
838
839                let store = get_store(dir, None, true).await;
840
841                let account = Account::with_device_id(&user_id, device_id);
842
843                store.save_pending_changes(PendingChanges { account: Some(account), })
844                    .await
845                    .expect("Can't save account");
846
847                let own_identity = get_own_identity();
848
849                let changes = Changes {
850                    identities: IdentityChanges {
851                        changed: vec![own_identity.clone().into()],
852                        ..Default::default()
853                    },
854                    ..Default::default()
855                };
856
857                store.save_changes(changes).await.expect("Can't save identity");
858
859                drop(store);
860
861                let store = get_store(dir, None, false).await;
862
863                store.load_account().await.unwrap();
864
865                let loaded_user =
866                    store.get_user_identity(own_identity.user_id()).await.unwrap().unwrap();
867
868                assert_eq!(loaded_user.master_key(), own_identity.master_key());
869                assert_eq!(loaded_user.self_signing_key(), own_identity.self_signing_key());
870                assert_eq!(loaded_user.own().unwrap().clone(), own_identity.clone());
871
872                let other_identity = get_other_identity();
873
874                let changes = Changes {
875                    identities: IdentityChanges {
876                        changed: vec![other_identity.clone().into()],
877                        ..Default::default()
878                    },
879                    ..Default::default()
880                };
881
882                store.save_changes(changes).await.unwrap();
883
884                let loaded_user =
885                    store.get_user_identity(other_identity.user_id()).await.unwrap().unwrap();
886
887                assert_eq!(loaded_user.master_key(), other_identity.master_key());
888                assert_eq!(loaded_user.self_signing_key(), other_identity.self_signing_key());
889                assert_eq!(loaded_user.user_id(), other_identity.user_id());
890                assert_eq!(loaded_user.other().unwrap().clone(), other_identity);
891
892                own_identity.mark_as_verified();
893
894                let changes = Changes {
895                    identities: IdentityChanges {
896                        changed: vec![own_identity.into()],
897                        ..Default::default()
898                    },
899                    ..Default::default()
900                };
901
902                store.save_changes(changes).await.unwrap();
903                let loaded_user = store.get_user_identity(&user_id).await.unwrap().unwrap();
904                assert!(loaded_user.own().unwrap().is_verified())
905            }
906
907            #[async_test]
908            async fn test_private_identity_saving() {
909                let (_, store) = get_loaded_store("private_identity_saving").await;
910                assert!(store.load_identity().await.unwrap().is_none());
911                let identity = PrivateCrossSigningIdentity::new(alice_id().to_owned());
912
913                let changes =
914                    Changes { private_identity: Some(identity.clone()), ..Default::default() };
915
916                store.save_changes(changes).await.unwrap();
917                let loaded_identity = store.load_identity().await.unwrap().unwrap();
918                assert_eq!(identity.user_id(), loaded_identity.user_id());
919            }
920
921            #[async_test]
922            async fn test_olm_hash_saving() {
923                let (_, store) = get_loaded_store("olm_hash_saving").await;
924
925                let hash = OlmMessageHash {
926                    sender_key: "test_sender".to_owned(),
927                    hash: "test_hash".to_owned(),
928                };
929
930                let mut changes = Changes::default();
931                changes.message_hashes.push(hash.clone());
932
933                assert!(!store.is_message_known(&hash).await.unwrap());
934                store.save_changes(changes).await.unwrap();
935                assert!(store.is_message_known(&hash).await.unwrap());
936            }
937
938            #[async_test]
939            async fn test_key_request_saving() {
940                let (account, store) = get_loaded_store("key_request_saving").await;
941                let sender_key =
942                    Curve25519PublicKey::from_base64("Nn0L2hkcCMFKqynTjyGsJbth7QrVmX3lbrksMkrGOAw")
943                        .unwrap();
944
945                let id = TransactionId::new();
946                let info: SecretInfo = MegolmV1AesSha2Content {
947                    room_id: room_id!("!test:localhost").to_owned(),
948                    sender_key,
949                    session_id: "test_session_id".to_owned(),
950                }
951                .into();
952
953                let request = GossipRequest {
954                    request_recipient: account.user_id().to_owned(),
955                    request_id: id.clone(),
956                    info: info.clone(),
957                    sent_out: false,
958                };
959
960                assert!(store.get_outgoing_secret_requests(&id).await.unwrap().is_none());
961
962                let mut changes = Changes::default();
963                changes.key_requests.push(request.clone());
964                store.save_changes(changes).await.unwrap();
965
966                let request = Some(request);
967
968                let stored_request = store.get_outgoing_secret_requests(&id).await.unwrap();
969                assert_eq!(request, stored_request);
970
971                let stored_request = store.get_secret_request_by_info(&info).await.unwrap();
972                assert_eq!(request, stored_request);
973                assert!(!store.get_unsent_secret_requests().await.unwrap().is_empty());
974
975                let request = GossipRequest {
976                    request_recipient: account.user_id().to_owned(),
977                    request_id: id.clone(),
978                    info: info.clone(),
979                    sent_out: true,
980                };
981
982                let mut changes = Changes::default();
983                changes.key_requests.push(request.clone());
984                store.save_changes(changes).await.unwrap();
985
986                assert!(store.get_unsent_secret_requests().await.unwrap().is_empty());
987                let stored_request = store.get_outgoing_secret_requests(&id).await.unwrap();
988                assert_eq!(Some(request), stored_request);
989
990                store.delete_outgoing_secret_requests(&id).await.unwrap();
991
992                let stored_request = store.get_outgoing_secret_requests(&id).await.unwrap();
993                assert_eq!(None, stored_request);
994
995                let stored_request = store.get_secret_request_by_info(&info).await.unwrap();
996                assert_eq!(None, stored_request);
997                assert!(store.get_unsent_secret_requests().await.unwrap().is_empty());
998            }
999
1000            #[async_test]
1001            async fn test_gossipped_secret_saving() {
1002                let (account, store) = get_loaded_store("gossipped_secret_saving").await;
1003
1004                let secret = "It is a secret to everybody";
1005
1006                let id = TransactionId::new();
1007                let info: SecretInfo = MegolmV1AesSha2Content {
1008                    room_id: room_id!("!test:localhost").to_owned(),
1009                    sender_key: account.identity_keys().curve25519,
1010                    session_id: "test_session_id".to_owned(),
1011                }
1012                .into();
1013
1014                let gossip_request = GossipRequest {
1015                    request_recipient: account.user_id().to_owned(),
1016                    request_id: id.clone(),
1017                    info: info.clone(),
1018                    sent_out: true,
1019                };
1020
1021                let mut event = DecryptedSecretSendEvent {
1022                    sender: account.user_id().to_owned(),
1023                    recipient: account.user_id().to_owned(),
1024                    keys: OlmV1Keys {
1025                        ed25519: account.identity_keys().ed25519,
1026                    },
1027                    recipient_keys: OlmV1Keys {
1028                        ed25519: account.identity_keys().ed25519,
1029                    },
1030                    sender_device_keys: None,
1031                    content: SecretSendContent::new(id.to_owned(), secret.to_owned()),
1032                };
1033
1034                let value = GossippedSecret {
1035                    secret_name: SecretName::RecoveryKey,
1036                    gossip_request: gossip_request.to_owned(),
1037                    event: event.to_owned(),
1038                };
1039
1040                assert!(
1041                    store.get_secrets_from_inbox(&SecretName::RecoveryKey).await.unwrap().is_empty(),
1042                    "No secret should initially be found in the store"
1043                );
1044
1045                let mut changes = Changes::default();
1046                changes.secrets.push(value);
1047                store.save_changes(changes).await.unwrap();
1048
1049                let restored = store.get_secrets_from_inbox(&SecretName::RecoveryKey).await.unwrap();
1050                let first_secret = restored.first().expect("We should have restored a secret now");
1051                assert_eq!(first_secret.event.content.secret, secret);
1052                assert_eq!(restored.len(), 1, "We should only have one secret stored for now");
1053
1054                event.content.request_id = TransactionId::new();
1055                let another_secret = GossippedSecret {
1056                    secret_name: SecretName::RecoveryKey,
1057                    gossip_request,
1058                    event,
1059                };
1060
1061                let mut changes = Changes::default();
1062                changes.secrets.push(another_secret);
1063                store.save_changes(changes).await.unwrap();
1064
1065                let restored = store.get_secrets_from_inbox(&SecretName::RecoveryKey).await.unwrap();
1066                assert_eq!(restored.len(), 2, "We should only have two secrets stored");
1067
1068                let restored = store.get_secrets_from_inbox(&SecretName::CrossSigningMasterKey).await.unwrap();
1069                assert!(restored.is_empty(), "We should not have secrets of a different type stored");
1070
1071                store.delete_secrets_from_inbox(&SecretName::RecoveryKey).await.unwrap();
1072
1073                let restored = store.get_secrets_from_inbox(&SecretName::RecoveryKey).await.unwrap();
1074                assert!(restored.is_empty(), "We should not have any secrets after we have deleted them");
1075            }
1076
1077            #[async_test]
1078            async fn test_withheld_info_storage() {
1079                let (account, store) = get_loaded_store("withheld_info_storage").await;
1080
1081                let mut info_list: BTreeMap<_, BTreeMap<_, _>> = BTreeMap::new();
1082
1083                let user_id = account.user_id().to_owned();
1084                let room_id = room_id!("!DwLygpkclUAfQNnfva:example.com");
1085                let session_id_1 = "GBnDxGP9i3IkPsz3/ihNr6P7qjIXxSRVWZ1MYmSn09w";
1086                let session_id_2 = "IDLtnNCH2kIr3xIf1B7JFkGpQmTjyMca2jww+X6zeOE";
1087
1088                let content = RoomKeyWithheldContent::MegolmV1AesSha2(
1089                    MegolmV1AesSha2WithheldContent::Unverified(
1090                        CommonWithheldCodeContent::new(
1091                            room_id.to_owned(),
1092                            session_id_1.into(),
1093                            Curve25519PublicKey::from_base64(
1094                                "9n7mdWKOjr9c4NTlG6zV8dbFtNK79q9vZADoh7nMUwA",
1095                            )
1096                            .unwrap(),
1097                            "DEVICEID".into(),
1098                        )
1099                        .into(),
1100                    ),
1101                );
1102                let event = ToDeviceEvent::new(user_id.to_owned(), content);
1103                info_list
1104                    .entry(room_id.to_owned())
1105                    .or_default()
1106                    .insert(session_id_1.to_owned(), event);
1107
1108                let content = RoomKeyWithheldContent::MegolmV1AesSha2(
1109                    MegolmV1AesSha2WithheldContent::BlackListed(
1110                        CommonWithheldCodeContent::new(
1111                            room_id.to_owned(),
1112                            session_id_2.into(),
1113                            Curve25519PublicKey::from_base64(
1114                                "9n7mdWKOjr9c4NTlG6zV8dbFtNK79q9vZADoh7nMUwA",
1115                            )
1116                            .unwrap(),
1117                            "DEVICEID".into(),
1118                        )
1119                        .into(),
1120                    ),
1121                );
1122                let event = ToDeviceEvent::new(user_id.to_owned(), content);
1123                info_list
1124                    .entry(room_id.to_owned())
1125                    .or_default()
1126                    .insert(session_id_2.to_owned(), event);
1127
1128                let changes = Changes { withheld_session_info: info_list, ..Default::default() };
1129                store.save_changes(changes).await.unwrap();
1130
1131                let is_withheld = store.get_withheld_info(room_id, session_id_1).await.unwrap();
1132
1133                assert_matches!(
1134                    is_withheld, Some(event)
1135                    if event.content.algorithm() == EventEncryptionAlgorithm::MegolmV1AesSha2 &&
1136                    event.content.withheld_code() == WithheldCode::Unverified
1137                );
1138
1139                let is_withheld = store.get_withheld_info(room_id, session_id_2).await.unwrap();
1140
1141                assert_matches!(
1142                    is_withheld, Some(event)
1143                    if event.content.algorithm() == EventEncryptionAlgorithm::MegolmV1AesSha2 &&
1144                    event.content.withheld_code() == WithheldCode::Blacklisted
1145                );
1146
1147                let other_room_id = room_id!("!nQRyiRFuyUhXeaQfiR:example.com");
1148
1149                let is_withheld =
1150                    store.get_withheld_info(other_room_id, session_id_2).await.unwrap();
1151
1152                assert!(is_withheld.is_none());
1153            }
1154
1155            #[async_test]
1156            async fn test_room_settings_saving() {
1157                let (_, store) = get_loaded_store("room_settings_saving").await;
1158
1159                let room_1 = room_id!("!test_1:localhost");
1160                let settings_1 = RoomSettings {
1161                    algorithm: EventEncryptionAlgorithm::MegolmV1AesSha2,
1162                    only_allow_trusted_devices: true,
1163                    session_rotation_period: Some(Duration::from_secs(10)),
1164                    session_rotation_period_messages: Some(123),
1165                };
1166
1167                let room_2 = room_id!("!test_2:localhost");
1168                let settings_2 = RoomSettings {
1169                    algorithm: EventEncryptionAlgorithm::OlmV1Curve25519AesSha2,
1170                    only_allow_trusted_devices: false,
1171                    ..Default::default()
1172                };
1173
1174                let room_3 = room_id!("!test_3:localhost");
1175
1176                let changes = Changes {
1177                    room_settings: HashMap::from([
1178                        (room_1.into(), settings_1.clone()),
1179                        (room_2.into(), settings_2.clone()),
1180                    ]),
1181                    ..Default::default()
1182                };
1183
1184                store.save_changes(changes).await.unwrap();
1185
1186                let loaded_settings_1 = store.get_room_settings(room_1).await.unwrap();
1187                assert_eq!(Some(settings_1), loaded_settings_1);
1188
1189                let loaded_settings_2 = store.get_room_settings(room_2).await.unwrap();
1190                assert_eq!(Some(settings_2), loaded_settings_2);
1191
1192                let loaded_settings_3 = store.get_room_settings(room_3).await.unwrap();
1193                assert_eq!(None, loaded_settings_3);
1194            }
1195
1196            #[async_test]
1197            async fn test_backup_keys_saving() {
1198                let (_account, store) = get_loaded_store("backup_keys_saving").await;
1199
1200                let restored = store.load_backup_keys().await.unwrap();
1201                assert!(restored.decryption_key.is_none(), "Initially no backup decryption key should be present");
1202
1203                let backup_decryption_key = Some(BackupDecryptionKey::new().unwrap());
1204
1205                let changes = Changes { backup_decryption_key, ..Default::default() };
1206                store.save_changes(changes).await.unwrap();
1207
1208                let restored = store.load_backup_keys().await.unwrap();
1209                assert!(restored.decryption_key.is_some(), "We should be able to restore a backup decryption key");
1210                assert!(restored.backup_version.is_none(), "The backup version should still be None");
1211
1212                let changes = Changes { backup_version: Some("some_version".to_owned()), ..Default::default() };
1213                store.save_changes(changes).await.unwrap();
1214
1215                let restored = store.load_backup_keys().await.unwrap();
1216                assert!(restored.decryption_key.is_some(), "The backup decryption key should still be known");
1217                assert!(restored.backup_version.is_some(), "The backup version should now be Some as well");
1218            }
1219
1220            #[async_test]
1221            async fn test_dehydration_pickle_key_saving() {
1222                let (_account, store) = get_loaded_store("dehydration_pickle_key_saving").await;
1223
1224                let restored = store.load_dehydrated_device_pickle_key().await.unwrap();
1225                assert!(restored.is_none(), "Initially no pickle key should be present");
1226
1227                let dehydrated_device_pickle_key = Some(DehydratedDeviceKey::new().unwrap());
1228                let exported_base64 = dehydrated_device_pickle_key.clone().unwrap().to_base64();
1229
1230                let changes = Changes { dehydrated_device_pickle_key, ..Default::default() };
1231                store.save_changes(changes).await.unwrap();
1232
1233                let restored = store.load_dehydrated_device_pickle_key().await.unwrap();
1234                assert!(restored.is_some(), "We should be able to restore a pickle key");
1235                assert_eq!(restored.unwrap().to_base64(), exported_base64);
1236
1237                // If None, should not clear the existing saved key
1238                let changes = Changes { dehydrated_device_pickle_key: None, ..Default::default() };
1239                store.save_changes(changes).await.unwrap();
1240
1241                let restored = store.load_dehydrated_device_pickle_key().await.unwrap();
1242                assert!(restored.is_some(), "We should be able to restore a pickle key");
1243                assert_eq!(restored.unwrap().to_base64(), exported_base64);
1244
1245            }
1246
1247             #[async_test]
1248            async fn test_delete_dehydration_pickle_key() {
1249                let (_account, store) = get_loaded_store("delete_dehydration_pickle_key").await;
1250
1251                let dehydrated_device_pickle_key = DehydratedDeviceKey::new().unwrap();
1252
1253                let changes = Changes { dehydrated_device_pickle_key: Some(dehydrated_device_pickle_key), ..Default::default() };
1254                store.save_changes(changes).await.unwrap();
1255
1256                let restored = store.load_dehydrated_device_pickle_key().await.unwrap();
1257                assert!(restored.is_some(), "We should be able to restore a pickle key");
1258
1259                store.delete_dehydrated_device_pickle_key().await.unwrap();
1260
1261                let restored = store.load_dehydrated_device_pickle_key().await.unwrap();
1262                assert!(restored.is_none(), "The previously saved key should be deleted");
1263
1264            }
1265
1266
1267            #[async_test]
1268            async fn test_custom_value_saving() {
1269                let (_, store) = get_loaded_store("custom_value_saving").await;
1270                store.set_custom_value("A", "Hello".as_bytes().to_vec()).await.unwrap();
1271
1272                let loaded_1 = store.get_custom_value("A").await.unwrap();
1273                assert_eq!(Some("Hello".as_bytes().to_vec()), loaded_1);
1274
1275                let loaded_2 = store.get_custom_value("B").await.unwrap();
1276                assert_eq!(None, loaded_2);
1277            }
1278
1279            fn session_info(session: &InboundGroupSession) -> (&RoomId, &str) {
1280                (&session.room_id(), &session.session_id())
1281            }
1282
1283            async fn create_session(
1284                account: &Account,
1285                device_curve_key: &Curve25519PublicKey,
1286                sender_data_type: SenderDataType,
1287            ) -> InboundGroupSession {
1288                let sender_data = match sender_data_type {
1289                    SenderDataType::UnknownDevice => {
1290                        SenderData::UnknownDevice { legacy_session: false, owner_check_failed: false }
1291                    }
1292                    SenderDataType::DeviceInfo => SenderData::DeviceInfo {
1293                        device_keys: account.device_keys().clone(),
1294                        legacy_session: false,
1295                    },
1296                    SenderDataType::VerificationViolation => panic!("VerificationViolation not supported"),
1297                    SenderDataType::SenderUnverified=> panic!("SenderUnverified not supported"),
1298                    SenderDataType::SenderVerified => panic!("SenderVerified not supported"),
1299                };
1300
1301                let session_key = GroupSession::new(SessionConfig::default()).session_key();
1302
1303                InboundGroupSession::new(
1304                    device_curve_key.clone(),
1305                    account.device_keys().ed25519_key().unwrap(),
1306                    room_id!("!r:s.co"),
1307                    &session_key,
1308                    sender_data,
1309                    EventEncryptionAlgorithm::MegolmV1AesSha2,
1310                    None,
1311                )
1312                .unwrap()
1313            }
1314        }
1315    };
1316}
1317
1318#[allow(unused_macros)]
1319#[macro_export]
1320macro_rules! cryptostore_integration_tests_time {
1321    () => {
1322        mod cryptostore_integration_tests_time {
1323            use std::time::Duration;
1324
1325            use matrix_sdk_test::async_test;
1326            use $crate::store::CryptoStore as _;
1327
1328            use super::cryptostore_integration_tests::*;
1329
1330            #[async_test]
1331            async fn test_lease_locks() {
1332                let (_account, store) = get_loaded_store("lease_locks").await;
1333
1334                let acquired0 = store.try_take_leased_lock(0, "key", "alice").await.unwrap();
1335                assert!(acquired0);
1336
1337                // Should extend the lease automatically (same holder).
1338                let acquired2 = store.try_take_leased_lock(300, "key", "alice").await.unwrap();
1339                assert!(acquired2);
1340
1341                // Should extend the lease automatically (same holder + time is ok).
1342                let acquired3 = store.try_take_leased_lock(300, "key", "alice").await.unwrap();
1343                assert!(acquired3);
1344
1345                // Another attempt at taking the lock should fail, because it's taken.
1346                let acquired4 = store.try_take_leased_lock(300, "key", "bob").await.unwrap();
1347                assert!(!acquired4);
1348
1349                // Even if we insist.
1350                let acquired5 = store.try_take_leased_lock(300, "key", "bob").await.unwrap();
1351                assert!(!acquired5);
1352
1353                // That's a nice test we got here, go take a little nap.
1354                tokio::time::sleep(Duration::from_millis(50)).await;
1355
1356                // Still too early.
1357                let acquired55 = store.try_take_leased_lock(300, "key", "bob").await.unwrap();
1358                assert!(!acquired55);
1359
1360                // Ok you can take another nap then.
1361                tokio::time::sleep(Duration::from_millis(250)).await;
1362
1363                // At some point, we do get the lock.
1364                let acquired6 = store.try_take_leased_lock(0, "key", "bob").await.unwrap();
1365                assert!(acquired6);
1366
1367                tokio::time::sleep(Duration::from_millis(1)).await;
1368
1369                // The other gets it almost immediately too.
1370                let acquired7 = store.try_take_leased_lock(0, "key", "alice").await.unwrap();
1371                assert!(acquired7);
1372
1373                tokio::time::sleep(Duration::from_millis(1)).await;
1374
1375                // But when we take a longer lease...
1376                let acquired8 = store.try_take_leased_lock(300, "key", "bob").await.unwrap();
1377                assert!(acquired8);
1378
1379                // It blocks the other user.
1380                let acquired9 = store.try_take_leased_lock(300, "key", "alice").await.unwrap();
1381                assert!(!acquired9);
1382
1383                // We can hold onto our lease.
1384                let acquired10 = store.try_take_leased_lock(300, "key", "bob").await.unwrap();
1385                assert!(acquired10);
1386            }
1387        }
1388    };
1389}