fix(updater): retain two verified backup generations

This commit is contained in:
2026-10-02 15:27:07 +02:00
parent 23d49f7186
commit b01cf2c207
5 changed files with 434 additions and 6 deletions

View File

@@ -646,6 +646,39 @@ class UpdateTests(unittest.TestCase):
self.assertFalse((self.root / '.updates/installed.json').exists())
self.assertEqual(self.runner.calls[-1][-3:], ['backend', 'frontend', 'traefik'])
def test_backup_retention_runs_only_after_successful_public_verification(self):
def prune():
self.assertEqual(self.updater.status()['status'], 'succeeded')
self.assertTrue(any(url.endswith('/api/health') for url in self.http.requests))
return {'retained': [], 'removed': [], 'skipped': []}
with patch.object(self.updater, '_prune_backups', side_effect=prune) as cleanup:
self.run_update()
cleanup.assert_called_once()
def test_failed_update_never_prunes_backups(self):
self.http.bad_health = True
with patch.object(self.updater, '_prune_backups') as cleanup:
with self.assertRaises(u.UpdateError):
self.run_update()
cleanup.assert_not_called()
def test_retention_error_does_not_fail_update_or_stop_the_new_application(self):
with patch.object(self.updater, '_prune_backups', side_effect=OSError('disk error')):
result = self.run_update()
self.assertEqual(result['status'], 'succeeded')
self.assertEqual(result['backupRetention']['status'], 'warning')
self.assertEqual(u.read_json(self.updater.home / 'backup-retention.json')['status'], 'warning')
self.assertFalse(result['recoveryRequired'])
self.assertEqual(sum('stop' in args for args in self.runner.calls), 1)
def test_interrupt_during_retention_preserves_completed_update(self):
with patch.object(self.updater, '_prune_backups', side_effect=KeyboardInterrupt):
with self.assertRaises(KeyboardInterrupt):
self.run_update()
self.assertEqual(self.updater.status()['status'], 'succeeded')
self.assertFalse(self.updater.status()['recoveryRequired'])
self.assertEqual(sum('stop' in args for args in self.runner.calls), 1)
def test_resolve_requires_a_working_manually_recovered_installation(self):
self.runner.fail = lambda args: 'migrate' in args
with self.assertRaises(u.UpdateError):