|
3 | 3 | from collections import OrderedDict |
4 | 4 | from collective.iconifiedcategory.utils import calculate_category_id |
5 | 5 | from datetime import date |
| 6 | +from datetime import datetime |
6 | 7 | from datetime import timedelta |
7 | 8 | from imio.esign.config import get_esign_registry_max_session_size |
| 9 | +from imio.esign.config import set_esign_registry_auto_cleanup_days |
8 | 10 | from imio.esign.config import set_esign_registry_external_watchers |
9 | 11 | from imio.esign.config import set_esign_registry_max_session_size |
10 | 12 | from imio.esign.testing import IMIO_ESIGN_INTEGRATION_TESTING |
11 | 13 | from imio.esign.utils import add_files_to_session |
| 14 | +from imio.esign.utils import cleanup_expired_sessions |
12 | 15 | from imio.esign.utils import create_external_session |
13 | 16 | from imio.esign.utils import get_file_download_url |
14 | 17 | from imio.esign.utils import get_file_info |
@@ -810,6 +813,108 @@ def test_create_external_session_both_payload(self): |
810 | 813 | }, |
811 | 814 | ) |
812 | 815 |
|
| 816 | + def test_cleanup_expired_sessions(self): |
| 817 | + """Auto-cleanup removes expired finalized sessions and respects the delay and throttle.""" |
| 818 | + signers = [("user1", "user1@sign.com", "User 1", "Position 1")] |
| 819 | + annot = get_session_annotation() |
| 820 | + self.addCleanup(set_esign_registry_auto_cleanup_days, 100) |
| 821 | + |
| 822 | + # --- Eligibility: only finalized sessions are cleaned up --- |
| 823 | + |
| 824 | + # Draft session with old last_update: never removed |
| 825 | + sid_draft, session_draft = add_files_to_session(signers, (self.uids[0],), discriminators=("draft",)) |
| 826 | + session_draft["last_update"] = datetime.now() - timedelta(days=200) |
| 827 | + annot["last_cleanup"] = datetime.min |
| 828 | + cleanup_expired_sessions() |
| 829 | + self.assertIn(sid_draft, annot["sessions"]) |
| 830 | + self.assertIn("last_cleanup", annot) |
| 831 | + |
| 832 | + # Non-finalized states (sent, to_sign, returned, etc.): never removed regardless of age |
| 833 | + for state in ("sent", "to_sign", "returned", "refused", "signed", "errored"): |
| 834 | + sid, session = add_files_to_session( |
| 835 | + signers, (self.uids[1],), discriminators=(state,) |
| 836 | + ) |
| 837 | + session["state"] = state |
| 838 | + session["last_update"] = datetime.now() - timedelta(days=200) |
| 839 | + annot["last_cleanup"] = datetime.min |
| 840 | + cleanup_expired_sessions() |
| 841 | + self.assertIn(sid, annot["sessions"], "State %s should not be cleaned up" % state) |
| 842 | + del annot["sessions"][sid] # clean up manually for next iteration |
| 843 | + |
| 844 | + # --- Expiry based on last_update (fallback when to_sign_date absent) --- |
| 845 | + |
| 846 | + # Finalized, last_update within window: not removed |
| 847 | + sid_recent_fin, session_recent_fin = add_files_to_session( |
| 848 | + signers, (self.uids[1],), discriminators=("recent_fin",) |
| 849 | + ) |
| 850 | + session_recent_fin["state"] = "finalized" |
| 851 | + session_recent_fin["last_update"] = datetime.now() - timedelta(days=50) |
| 852 | + annot["last_cleanup"] = datetime.min |
| 853 | + cleanup_expired_sessions() |
| 854 | + self.assertIn(sid_recent_fin, annot["sessions"]) |
| 855 | + |
| 856 | + # Finalized, last_update expired (> 100 days), no to_sign_date: removed |
| 857 | + sid_old_fin, session_old_fin = add_files_to_session( |
| 858 | + signers, (self.uids[2],), discriminators=("old_fin",) |
| 859 | + ) |
| 860 | + session_old_fin["state"] = "finalized" |
| 861 | + session_old_fin["last_update"] = datetime.now() - timedelta(days=101) |
| 862 | + annot["last_cleanup"] = datetime.min |
| 863 | + cleanup_expired_sessions() |
| 864 | + self.assertNotIn(sid_old_fin, annot["sessions"]) |
| 865 | + self.assertNotIn(self.uids[2], annot["uids"]) |
| 866 | + self.assertIn(sid_recent_fin, annot["sessions"]) # recent session untouched |
| 867 | + |
| 868 | + # --- Expiry based on to_sign_date (takes priority over last_update) --- |
| 869 | + |
| 870 | + # to_sign_date expired but last_update recent: to_sign_date wins → removed |
| 871 | + sid_ts_old, session_ts_old = add_files_to_session( |
| 872 | + signers, (self.uids[2],), discriminators=("ts_old",) |
| 873 | + ) |
| 874 | + session_ts_old["state"] = "finalized" |
| 875 | + session_ts_old["to_sign_date"] = datetime.now() - timedelta(days=101) |
| 876 | + session_ts_old["last_update"] = datetime.now() - timedelta(days=1) |
| 877 | + annot["last_cleanup"] = datetime.min |
| 878 | + cleanup_expired_sessions() |
| 879 | + self.assertNotIn(sid_ts_old, annot["sessions"]) |
| 880 | + |
| 881 | + # to_sign_date within window but last_update old: to_sign_date wins → kept |
| 882 | + sid_ts_recent, session_ts_recent = add_files_to_session( |
| 883 | + signers, (self.uids[2],), discriminators=("ts_recent",) |
| 884 | + ) |
| 885 | + session_ts_recent["state"] = "finalized" |
| 886 | + session_ts_recent["to_sign_date"] = datetime.now() - timedelta(days=50) |
| 887 | + session_ts_recent["last_update"] = datetime.now() - timedelta(days=200) |
| 888 | + annot["last_cleanup"] = datetime.min |
| 889 | + cleanup_expired_sessions() |
| 890 | + self.assertIn(sid_ts_recent, annot["sessions"]) |
| 891 | + |
| 892 | + # --- Throttle --- |
| 893 | + |
| 894 | + sid_throttle, session_throttle = add_files_to_session( |
| 895 | + signers, (self.uids[3],), discriminators=("throttle",) |
| 896 | + ) |
| 897 | + session_throttle["state"] = "finalized" |
| 898 | + session_throttle["last_update"] = datetime.now() - timedelta(days=101) |
| 899 | + annot["last_cleanup"] = datetime.now() - timedelta(hours=1) # ran 1h ago |
| 900 | + cleanup_expired_sessions() |
| 901 | + self.assertIn(sid_throttle, annot["sessions"]) # throttled: skipped |
| 902 | + |
| 903 | + # --- Disabled (0 days) --- |
| 904 | + |
| 905 | + set_esign_registry_auto_cleanup_days(0) |
| 906 | + annot["last_cleanup"] = datetime.min |
| 907 | + cleanup_expired_sessions() |
| 908 | + self.assertIn(sid_throttle, annot["sessions"]) # disabled: skipped |
| 909 | + |
| 910 | + # --- Custom delay: 10 days --- |
| 911 | + |
| 912 | + set_esign_registry_auto_cleanup_days(10) |
| 913 | + # session_throttle has last_update 101 days ago → expired under 10-day rule |
| 914 | + annot["last_cleanup"] = datetime.min |
| 915 | + cleanup_expired_sessions() |
| 916 | + self.assertNotIn(sid_throttle, annot["sessions"]) |
| 917 | + |
813 | 918 |
|
814 | 919 | # example of annotation content |
815 | 920 | """ |
|
0 commit comments