Implement bounded primary archive transfer and explicit essentials capture
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a06ecb-456a-71c2-b41e-0755d336e883
This commit is contained in:
parent
69187c2f45
commit
4707bf08d7
4 changed files with 165 additions and 7 deletions
49
tests/test_backup_tiers.py
Normal file
49
tests/test_backup_tiers.py
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
import io
|
||||
from pathlib import Path
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
from unittest.mock import MagicMock,patch
|
||||
import zipfile
|
||||
sys.path.insert(0,str(Path(__file__).resolve().parents[1]/'scripts'))
|
||||
import scaleway_forgejo_archive as primary
|
||||
from capture_forgejo_archive import validate_archive
|
||||
|
||||
class BackupTiers(unittest.TestCase):
|
||||
def archive(self,path,package=False):
|
||||
with zipfile.ZipFile(path,'w') as z:
|
||||
z.writestr('forgejo-db.sql','fixture');z.writestr('repos/owner/repo.git/HEAD','ref: refs/heads/main')
|
||||
z.writestr('data/lfs/unique','keep');z.writestr('data/attachments/unique','keep')
|
||||
if package: z.writestr('data/packages/blob','bulk')
|
||||
def test_full_keeps_packages_essentials_rejects_them(self):
|
||||
with tempfile.TemporaryDirectory() as d:
|
||||
p=Path(d)/'archive.zip';self.archive(p,True);validate_archive(p)
|
||||
with self.assertRaises(ValueError): validate_archive(p,'essentials')
|
||||
def test_essentials_keeps_unique_files(self):
|
||||
with tempfile.TemporaryDirectory() as d:
|
||||
p=Path(d)/'archive.zip';self.archive(p);validate_archive(p,'essentials')
|
||||
def client(self):
|
||||
c=MagicMock();c.create_multipart_upload.return_value={'UploadId':'fixture'}
|
||||
c.upload_part.return_value={'ETag':'part-etag'}
|
||||
c.complete_multipart_upload.return_value={'VersionId':'fixture-version'}
|
||||
return c
|
||||
def test_failed_upload_aborts_only_its_multipart(self):
|
||||
with tempfile.TemporaryDirectory() as d:
|
||||
p=Path(d)/'source';p.write_bytes(b'abc');c=self.client();c.upload_part.side_effect=RuntimeError('fixture')
|
||||
receipt={}
|
||||
with self.assertRaises(RuntimeError): primary.transfer(c,p,Path(d)/'out',receipt)
|
||||
c.abort_multipart_upload.assert_called_once();c.delete_object.assert_not_called()
|
||||
self.assertTrue(receipt['multipart_aborted'])
|
||||
def test_download_is_version_pinned_and_hash_verified(self):
|
||||
with tempfile.TemporaryDirectory() as d:
|
||||
p=Path(d)/'source';p.write_bytes(b'abc');c=self.client()
|
||||
c.get_object.return_value={'ContentLength':3,'Body':io.BytesIO(b'abc')}
|
||||
receipt={};primary.transfer(c,p,Path(d)/'out',receipt)
|
||||
self.assertEqual(c.get_object.call_args.kwargs['VersionId'],'fixture-version')
|
||||
self.assertTrue(receipt['download_hash_matches']);c.abort_multipart_upload.assert_not_called()
|
||||
def test_corrupt_download_does_not_pass(self):
|
||||
with tempfile.TemporaryDirectory() as d:
|
||||
p=Path(d)/'source';p.write_bytes(b'abc');c=self.client()
|
||||
c.get_object.return_value={'ContentLength':3,'Body':io.BytesIO(b'xyz')}
|
||||
with self.assertRaises(ValueError): primary.transfer(c,p,Path(d)/'out',{})
|
||||
c.delete_object.assert_not_called()
|
||||
Loading…
Add table
Add a link
Reference in a new issue