Release v0.1.29: media previews, clean composer, regional profiles and cloud retention

This commit is contained in:
Codex
2026-10-04 20:03:44 +08:00
parent 67709832c5
commit 693dd2a10a
17 changed files with 359 additions and 46 deletions
+30 -1
View File
@@ -89,7 +89,36 @@ class BackupTests(unittest.TestCase):
def test_baidu_success_is_separate_from_network_mount_and_requires_opt_in(self):
backup=self.source_file()
with patch.object(app.BAIDU,'upload',return_value={'fs_id':123}) as upload, patch.object(app.BAIDU,'public_config',return_value={'appFolder':'测试'}):
with patch.object(app.BAIDU,'upload',return_value={'fs_id':123}) as upload, patch.object(app.BAIDU,'public_config',return_value={'appFolder':'测试'}), patch.object(app.BAIDU,'verify_backup'), patch.object(app.BAIDU,'list_directory',return_value=[]):
result=backup.run();upload.assert_not_called();self.assertFalse(result['baiduOk'])
app.set_setting('backup_config',dict(backup.config(),baidu=True))
result=backup.run();self.assertTrue(result['baiduOk']);self.assertFalse(result['networkOk']);self.assertEqual(result['baiduFileId'],'123')
def test_cloud_cleanup_only_runs_after_verified_upload(self):
backup=self.source_file();app.set_setting('backup_config',dict(backup.config(),baidu=True))
with patch.object(app.BAIDU,'public_config',return_value={'appFolder':'测试'}), patch.object(app.BAIDU,'upload',return_value={'fs_id':123}), patch.object(backup,'prune_cloud') as prune:
with patch.object(app.BAIDU,'verify_backup',side_effect=RuntimeError('hash mismatch')):
result=backup.run();self.assertFalse(result['baiduOk']);prune.assert_not_called()
with patch.object(app.BAIDU,'verify_backup'):
result=backup.run();self.assertTrue(result['baiduOk']);prune.assert_called_once()
def test_retention_is_a_calendar_month_including_leap_and_year_boundaries(self):
for value, expected in [('2024-03-31','2024-02-29'),('2026-03-31','2026-02-28'),('2026-01-04','2025-12-04')]:
self.assertEqual(Backups.month_before(dt.datetime.fromisoformat(value)).date().isoformat(),expected)
def test_cloud_prune_limits_to_instance_and_expired_database_files(self):
backup=Backups(app);instance='a'*16;root='/apps/测试/数据库备份/'+instance
def name(stamp):return 'vision-'+instance+'-'+stamp+'.sqlite'
old=name('20260804T120000000000Z');nested=name('20260805T120000000000Z');recent=name('20261004T120000000000Z');boundary=name('20260904T120000000000Z')
rows=[dict(path=root+'/'+n,isdir=0) for n in (old,recent,boundary,'holiday.png','../'+old)]
rows+=[dict(path=root+'/'+nested,isdir=1),dict(path='/apps/其他/'+old,isdir=0)]
def listing(path):return rows if path==root else [dict(path=path+'/'+nested,isdir=0),dict(path=path+'/private.png',isdir=0)]
with patch.object(app.BAIDU,'public_config',return_value={'appFolder':'测试'}),patch.object(app.BAIDU,'list_directory',side_effect=listing),patch.object(app.BAIDU,'delete_backup_file') as delete:
result={};backup.prune_cloud(instance,root+'/'+recent,result,dt.datetime(2026,10,4,12,tzinfo=dt.timezone.utc))
self.assertEqual([c.args[0] for c in delete.call_args_list],[root+'/'+old,root+'/'+nested+'/'+nested]);self.assertEqual(result['cloudDeleted'],2)
def test_cloud_cleanup_failure_keeps_successful_new_backup(self):
backup=self.source_file();app.set_setting('backup_config',dict(backup.config(),baidu=True))
with patch.object(app.BAIDU,'public_config',return_value={'appFolder':'测试'}),patch.object(app.BAIDU,'upload',return_value={'fs_id':123}),patch.object(app.BAIDU,'verify_backup'),patch.object(backup,'prune_cloud',side_effect=RuntimeError('cleanup unavailable')):
result=backup.run()
self.assertTrue(result['baiduOk']);self.assertFalse(result['cloudCleanupOk']);self.assertNotIn('error',result)