1818import subprocess
1919import tarfile
2020import time
21- from dataclasses import dataclass
2221from pathlib import Path
2322from unittest .mock import patch
2423
2726from content_sync import snapshot
2827from content_sync .course_repository_ingest import (
2928 CourseRepositoryFetchError ,
29+ CourseRepositoryLimits ,
3030 fetch_course_repository_snapshot ,
3131 read_course_repository_checkout ,
3232)
3535SCRATCH_ROOT = PROJECT_ROOT / ".tmp" / "snapshot-resource-budgets"
3636
3737
38- @dataclass (frozen = True )
39- class _Limits :
40- """The tightest ceilings the budgets can be expressed against."""
41-
42- max_files : int = 1
43- max_total_bytes : int = 1
44- max_file_bytes : int = 1
45-
46-
47- def _build_tar (* specs : tuple [str , int , bytes , dict [str , str ] | None ]) -> bytes :
38+ def _build_tar (* specs : tuple [str , bytes , bytes , dict [str , str ] | None ]) -> bytes :
4839 """One tar session holding every spec: ``(name, type, content, pax)``."""
4940
5041 buffer = io .BytesIO ()
@@ -59,11 +50,11 @@ def _build_tar(*specs: tuple[str, int, bytes, dict[str, str] | None]) -> bytes:
5950 return buffer .getvalue ()
6051
6152
62- def _file (name : str , content : bytes = b"x" ) -> tuple [str , int , bytes , None ]:
53+ def _file (name : str , content : bytes = b"x" ) -> tuple [str , bytes , bytes , None ]:
6354 return (name , tarfile .REGTYPE , content , None )
6455
6556
66- def _dir (name : str ) -> tuple [str , int , bytes , None ]:
57+ def _dir (name : str ) -> tuple [str , bytes , bytes , None ]:
6758 return (name , tarfile .DIRTYPE , b"" , None )
6859
6960
@@ -147,7 +138,7 @@ def test_success_under_the_cap_returns_the_archive(self) -> None:
147138 self .assertEqual (
148139 snapshot .read_snapshot_archive (
149140 archive ,
150- limits = _Limits (max_files = 5 , max_total_bytes = 100 , max_file_bytes = 100 ),
141+ limits = CourseRepositoryLimits (max_files = 5 , max_total_bytes = 100 , max_file_bytes = 100 ),
151142 strip_root = False ,
152143 ),
153144 {"a.txt" : b"hello\n " },
@@ -217,7 +208,11 @@ def test_many_directory_entries_exhaust_the_structural_budget(self) -> None:
217208 archive = _build_tar (* [_dir (f"dir-{ index :03d} /" ) for index in range (100 )])
218209
219210 with self .assertRaises (snapshot .SnapshotError ) as raised :
220- snapshot .read_snapshot_archive (archive , limits = _Limits (), strip_root = False )
211+ snapshot .read_snapshot_archive (
212+ archive ,
213+ limits = CourseRepositoryLimits (max_files = 1 , max_total_bytes = 1 , max_file_bytes = 1 ),
214+ strip_root = False ,
215+ )
221216
222217 self .assertEqual (raised .exception .code , "archive_members_exceeded" )
223218
@@ -227,7 +222,7 @@ def test_legitimate_directories_do_not_consume_the_file_count(self) -> None:
227222
228223 result = snapshot .read_snapshot_archive (
229224 _build_tar (* specs ),
230- limits = _Limits (max_files = 10 , max_total_bytes = 100 , max_file_bytes = 10 ),
225+ limits = CourseRepositoryLimits (max_files = 10 , max_total_bytes = 100 , max_file_bytes = 10 ),
231226 strip_root = False ,
232227 )
233228
@@ -248,7 +243,9 @@ def test_a_compressed_metadata_bomb_is_bounded(self) -> None:
248243
249244 with self .assertRaises (snapshot .SnapshotError ) as raised :
250245 snapshot .read_snapshot_archive (
251- gzip .compress (_build_tar (* specs )), limits = _Limits (), strip_root = False
246+ gzip .compress (_build_tar (* specs )),
247+ limits = CourseRepositoryLimits (max_files = 1 , max_total_bytes = 1 , max_file_bytes = 1 ),
248+ strip_root = False ,
252249 )
253250
254251 self .assertEqual (raised .exception .code , "archive_expansion_exceeded" )
@@ -258,7 +255,7 @@ def test_symlinks_and_duplicates_are_still_refused(self) -> None:
258255 with self .assertRaises (snapshot .SnapshotError ) as raised :
259256 snapshot .read_snapshot_archive (
260257 _build_tar (link ),
261- limits = _Limits (max_files = 5 , max_total_bytes = 100 , max_file_bytes = 10 ),
258+ limits = CourseRepositoryLimits (max_files = 5 , max_total_bytes = 100 , max_file_bytes = 10 ),
262259 strip_root = False ,
263260 )
264261 self .assertEqual (raised .exception .code , "archive_entry_invalid" )
@@ -267,7 +264,7 @@ def test_symlinks_and_duplicates_are_still_refused(self) -> None:
267264 with self .assertRaises (snapshot .SnapshotError ) as raised :
268265 snapshot .read_snapshot_archive (
269266 duplicate ,
270- limits = _Limits (max_files = 5 , max_total_bytes = 100 , max_file_bytes = 10 ),
267+ limits = CourseRepositoryLimits (max_files = 5 , max_total_bytes = 100 , max_file_bytes = 10 ),
271268 strip_root = False ,
272269 )
273270 self .assertEqual (raised .exception .code , "duplicate_path" )
@@ -325,7 +322,9 @@ def test_a_budget_spent_on_the_headers_refuses_before_reading(self) -> None:
325322 owner = "owner" ,
326323 repository = "repo" ,
327324 commit_sha = "a" * 40 ,
328- limits = _Limits (max_files = 5 , max_total_bytes = 100 , max_file_bytes = 10 ),
325+ limits = CourseRepositoryLimits (
326+ max_files = 5 , max_total_bytes = 100 , max_file_bytes = 10
327+ ),
329328 )
330329
331330 self .assertEqual (raised .exception .code , "course_repository_fetch_timeout" )
@@ -344,7 +343,9 @@ def test_a_budget_spent_midstream_stops_the_reads(self) -> None:
344343 owner = "owner" ,
345344 repository = "repo" ,
346345 commit_sha = "a" * 40 ,
347- limits = _Limits (max_files = 5 , max_total_bytes = 100 , max_file_bytes = 10 ),
346+ limits = CourseRepositoryLimits (
347+ max_files = 5 , max_total_bytes = 100 , max_file_bytes = 10
348+ ),
348349 )
349350
350351 self .assertEqual (raised .exception .code , "course_repository_fetch_timeout" )
@@ -358,7 +359,7 @@ class TransportBudgetParityTests(SimpleTestCase):
358359 def test_a_structurally_exhausting_tree_refuses_identically (self ) -> None :
359360 deep = "/" .join (f"level-{ index :02d} " for index in range (100 ))
360361 root , commit_sha = _git_repo ("deep-tree" , file_relative = f"{ deep } /deepest.txt" )
361- limits = _Limits (max_files = 1 , max_total_bytes = 1_000_000 , max_file_bytes = 100 )
362+ limits = CourseRepositoryLimits (max_files = 1 , max_total_bytes = 1_000_000 , max_file_bytes = 100 )
362363
363364 with self .assertRaises (CourseRepositoryFetchError ) as pulled :
364365 read_course_repository_checkout (root , commit_sha = commit_sha , limits = limits )
0 commit comments