railiance-platform/tests/test_nextcloud_recovery_cleanup.py
codex a9c1da4bd7
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Bound rejected backup fixture cleanup to successful replacement recovery
Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a06ecb-456a-71c2-b41e-0755d336e883
2026-09-06 01:05:27 +02:00

53 lines
2.5 KiB
Python

import json
from pathlib import Path
import sys
import tempfile
import unittest
from unittest.mock import MagicMock, patch
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / 'scripts'))
import cleanup_nextcloud_recovery_fixture as cleanup
class RecoveryFixtureCleanup(unittest.TestCase):
def proof(self, directory, status='restored'):
path = Path(directory) / 'proof.json'
path.write_text(json.dumps({'status': status, 'cleanup': True,
'offsite_artifact': 'wp0029-recovery-forgejo-dump-20260905-verified.zip.age'}))
return path
def test_no_credentials_before_successful_recovery(self):
with tempfile.TemporaryDirectory() as directory, patch.object(cleanup, 'bao') as bao:
with self.assertRaises(Exception):
cleanup.run(self.proof(directory, 'failed'), {})
bao.assert_not_called()
def exercise(self, size):
opener = MagicMock()
head = MagicMock(status=200, headers={'Content-Length': str(size), 'ETag': '"fixture-version"'})
delete = MagicMock(status=204)
opener.open.side_effect = [MagicMock(__enter__=lambda _: head, __exit__=lambda *a: False),
MagicMock(__enter__=lambda _: delete, __exit__=lambda *a: False)]
with tempfile.TemporaryDirectory() as directory, \
patch.object(cleanup, 'bao'), \
patch.object(cleanup, 'data', return_value={'data': {'data': {'BACKUP_USERNAME': 'Backup', 'BACKUP_PASSWORD': 'fixture'}}}), \
patch.object(cleanup, 'quota', return_value={}), \
patch.object(cleanup.urllib.request, 'build_opener', return_value=opener):
receipt = {}
if size != cleanup.SIZE:
with self.assertRaises(Exception):
cleanup.run(self.proof(directory), receipt)
self.assertEqual(opener.open.call_count, 1)
else:
cleanup.run(self.proof(directory), receipt)
request = opener.open.call_args_list[1].args[0]
self.assertEqual(request.method, 'DELETE')
self.assertTrue(request.full_url.endswith('/forgejo/' + cleanup.ARTIFACT))
self.assertEqual(request.get_header('If-match'), '"fixture-version"')
self.assertEqual(receipt['status'], 'removed')
def test_mismatched_object_is_preserved(self):
self.exercise(1)
def test_exact_object_has_conditional_delete(self):
self.exercise(cleanup.SIZE)