@@ -4706,6 +4706,7 @@ mod tests {
4706
4706
use crate :: chatlist:: get_archived_cnt;
4707
4707
use crate :: constants:: { DC_GCL_ARCHIVED_ONLY , DC_GCL_NO_SPECIALS } ;
4708
4708
use crate :: headerdef:: HeaderDef ;
4709
+ use crate :: imex:: { has_backup, imex, ImexMode } ;
4709
4710
use crate :: message:: delete_msgs;
4710
4711
use crate :: receive_imf:: receive_imf;
4711
4712
use crate :: test_utils:: { sync, TestContext , TestContextManager , TimeShiftFalsePositiveNote } ;
@@ -7935,4 +7936,112 @@ mod tests {
7935
7936
7936
7937
Ok ( ( ) )
7937
7938
}
7939
+
7940
+ /// Test the case when Alice restores a backup older than 60 days
7941
+ /// with outdated member list.
7942
+ #[ tokio:: test( flavor = "multi_thread" , worker_threads = 2 ) ]
7943
+ async fn test_restore_backup_after_60_days ( ) -> Result < ( ) > {
7944
+ let backup_dir = tempfile:: tempdir ( ) ?;
7945
+
7946
+ let mut tcm = TestContextManager :: new ( ) ;
7947
+
7948
+ let alice = & tcm. alice ( ) . await ;
7949
+ let bob = & tcm. bob ( ) . await ;
7950
+ let fiona = & tcm. fiona ( ) . await ;
7951
+
7952
+ let bob_addr = bob. get_config ( Config :: Addr ) . await ?. unwrap ( ) ;
7953
+ let alice_bob_contact_id = Contact :: create ( alice, "Bob" , & bob_addr) . await ?;
7954
+
7955
+ let charlie_addr =
"[email protected] " ;
7956
+ let alice_charlie_contact_id = Contact :: create ( alice, "Charlie" , charlie_addr) . await ?;
7957
+
7958
+ let alice_chat_id =
7959
+ create_group_chat ( alice, ProtectionStatus :: Unprotected , "Group chat" ) . await ?;
7960
+ add_contact_to_chat ( alice, alice_chat_id, alice_bob_contact_id) . await ?;
7961
+ add_contact_to_chat ( alice, alice_chat_id, alice_charlie_contact_id) . await ?;
7962
+
7963
+ let alice_sent_promote = alice
7964
+ . send_text ( alice_chat_id, "Hi! I created a group." )
7965
+ . await ;
7966
+ let bob_rcvd_promote = bob. recv_msg ( & alice_sent_promote) . await ;
7967
+ let bob_chat_id = bob_rcvd_promote. chat_id ;
7968
+ bob_chat_id. accept ( bob) . await ?;
7969
+
7970
+ // Alice exports a backup.
7971
+ imex ( alice, ImexMode :: ExportBackup , backup_dir. path ( ) , None ) . await ?;
7972
+
7973
+ remove_contact_from_chat ( alice, alice_chat_id, alice_charlie_contact_id) . await ?;
7974
+ assert_eq ! ( get_chat_contacts( alice, alice_chat_id) . await ?. len( ) , 2 ) ;
7975
+ assert_eq ! ( get_past_chat_contacts( alice, alice_chat_id) . await ?. len( ) , 1 ) ;
7976
+
7977
+ let remove_message = alice. pop_sent_msg ( ) . await ;
7978
+ assert_eq ! ( remove_message. payload. contains( & charlie_addr) , true ) ;
7979
+ bob. recv_msg ( & remove_message) . await ;
7980
+
7981
+ // 60 days pass.
7982
+ SystemTime :: shift ( Duration :: from_secs ( 60 * 24 * 60 * 60 + 1 ) ) ;
7983
+
7984
+ assert_eq ! ( get_past_chat_contacts( alice, alice_chat_id) . await ?. len( ) , 0 ) ;
7985
+
7986
+ // Bob adds Fiona to the chat.
7987
+ let fiona_addr = fiona. get_config ( Config :: Addr ) . await ?. unwrap ( ) ;
7988
+ let bob_fiona_contact_id = Contact :: create ( bob, "Fiona" , & fiona_addr) . await ?;
7989
+ add_contact_to_chat ( bob, bob_chat_id, bob_fiona_contact_id) . await ?;
7990
+
7991
+ let add_message = bob. pop_sent_msg ( ) . await ;
7992
+ alice. recv_msg ( & add_message) . await ;
7993
+ let fiona_add_message = fiona. recv_msg ( & add_message) . await ;
7994
+ let fiona_chat_id = fiona_add_message. chat_id ;
7995
+
7996
+ // Fiona does not learn about Charlie,
7997
+ // even from `Chat-Group-Past-Members`, because tombstone has expired.
7998
+ assert_eq ! ( get_chat_contacts( fiona, fiona_chat_id) . await ?. len( ) , 3 ) ;
7999
+ assert_eq ! ( get_past_chat_contacts( fiona, fiona_chat_id) . await ?. len( ) , 0 ) ;
8000
+
8001
+ tcm. section ( "Alice imports old backup" ) ;
8002
+ let alice = & tcm. unconfigured ( ) . await ;
8003
+ let backup = has_backup ( alice, backup_dir. path ( ) ) . await ?;
8004
+ imex ( alice, ImexMode :: ImportBackup , backup. as_ref ( ) , None ) . await ?;
8005
+
8006
+ // Alice thinks Charlie is in the chat, but does not know about Fiona.
8007
+ assert_eq ! ( get_chat_contacts( alice, alice_chat_id) . await ?. len( ) , 3 ) ;
8008
+ assert_eq ! ( get_past_chat_contacts( alice, alice_chat_id) . await ?. len( ) , 0 ) ;
8009
+
8010
+ assert_eq ! ( get_chat_contacts( bob, bob_chat_id) . await ?. len( ) , 3 ) ;
8011
+ assert_eq ! ( get_past_chat_contacts( bob, bob_chat_id) . await ?. len( ) , 0 ) ;
8012
+
8013
+ assert_eq ! ( get_chat_contacts( fiona, fiona_chat_id) . await ?. len( ) , 3 ) ;
8014
+ assert_eq ! ( get_past_chat_contacts( fiona, fiona_chat_id) . await ?. len( ) , 0 ) ;
8015
+
8016
+ // Bob sends a text message to the chat, without a tombstone for Charlie.
8017
+ // Alice learns about Fiona.
8018
+ let bob_sent_text = bob. send_text ( alice_chat_id, "Message." ) . await ;
8019
+
8020
+ tcm. section ( "Alice sends a message to stale chat" ) ;
8021
+ let alice_sent_text = alice
8022
+ . send_text ( alice_chat_id, "Hi! I just restored a backup." )
8023
+ . await ;
8024
+
8025
+ tcm. section ( "Alice sent a message to stale chat" ) ;
8026
+ alice. recv_msg ( & bob_sent_text) . await ;
8027
+ fiona. recv_msg ( & bob_sent_text) . await ;
8028
+
8029
+ bob. recv_msg ( & alice_sent_text) . await ;
8030
+ fiona. recv_msg ( & alice_sent_text) . await ;
8031
+
8032
+ // This should not add or restore Charlie for Bob and Fiona,
8033
+ // Charlie is not part of the chat.
8034
+ assert_eq ! ( get_chat_contacts( bob, bob_chat_id) . await ?. len( ) , 3 ) ;
8035
+ assert_eq ! ( get_past_chat_contacts( bob, bob_chat_id) . await ?. len( ) , 0 ) ;
8036
+
8037
+ assert_eq ! ( get_chat_contacts( fiona, fiona_chat_id) . await ?. len( ) , 3 ) ;
8038
+ assert_eq ! ( get_past_chat_contacts( fiona, fiona_chat_id) . await ?. len( ) , 0 ) ;
8039
+
8040
+ // Alice should have also learned about Charlie not being part of the group
8041
+ // by receiving Bob's message.
8042
+ assert_eq ! ( get_chat_contacts( bob, bob_chat_id) . await ?. len( ) , 3 ) ;
8043
+ assert_eq ! ( get_past_chat_contacts( bob, bob_chat_id) . await ?. len( ) , 0 ) ;
8044
+
8045
+ Ok ( ( ) )
8046
+ }
7938
8047
}
0 commit comments