Coverage for tests/test_progress_file.py: 100%
63 statements
« prev ^ index » next coverage.py v7.16.0, created at 2026-11-09 00:25 +0000
« prev ^ index » next coverage.py v7.16.0, created at 2026-11-09 00:25 +0000
1import io 1hijklmn
2from datetime import datetime, timezone 1hijklmn
3from unittest.mock import Mock, call 1hijklmn
5import time_machine 1hijklmn
7from fastapi_cloud_cli.utils.progress_file import ProgressFile 1hijklmn
10def _make_file( 1hijklmn
11 content: bytes = b"hello world", name: str = "test.tar.gz"
12) -> io.BytesIO:
13 f = io.BytesIO(content) 1oCDapXQqEFbrYRsGHctZSuIJdv0TwKLex1UyMNfz2VAOPgB3W
14 f.name = name 1oCDapXQqEFbrYRsGHctZSuIJdv0TwKLex1UyMNfz2VAOPgB3W
15 return f 1oCDapXQqEFbrYRsGHctZSuIJdv0TwKLex1UyMNfz2VAOPgB3W
18def test_read_with_size() -> None: 1hijklmn
19 file = _make_file(b"abcdef") 1QRSTUVW
20 pf = ProgressFile(file, progress_callback=lambda _: None) 1QRSTUVW
22 assert pf.read(3) == b"abc" 1QRSTUVW
23 assert pf.read(3) == b"def" 1QRSTUVW
26def test_callback_not_called_within_interval() -> None: 1hijklmn
27 file = _make_file(b"abcdef") 1DFHJLNP
28 mock_callback = Mock() 1DFHJLNP
29 pf = ProgressFile(file, progress_callback=mock_callback) 1DFHJLNP
31 pf.read(3) # Should trigger callback 1DFHJLNP
32 pf.read(3) # Should NOT trigger 1DFHJLNP
34 mock_callback.assert_called_once_with(3) 1DFHJLNP
37def test_callback_called_after_interval_elapses() -> None: 1hijklmn
38 file = _make_file(b"abcdef") 1oqsuwyA
39 mock_callback = Mock() 1oqsuwyA
41 with time_machine.travel( 1oqsuwyA
42 datetime(2026, 1, 1, tzinfo=timezone.utc), tick=False
43 ) as traveller:
44 pf = ProgressFile(file, progress_callback=mock_callback) 1oqsuwyA
46 pf.read(3) 1oqsuwyA
47 traveller.shift(0.6) 1oqsuwyA
48 pf.read(3) 1oqsuwyA
50 mock_callback.assert_has_calls([call(3), call(6)]) 1oqsuwyA
53def test_callback_tracks_cumulative_bytes() -> None: 1hijklmn
54 file = _make_file(b"a" * 100) 1abcdefg
55 mock_callback = Mock() 1abcdefg
57 with time_machine.travel( 1abcdefg
58 datetime(2026, 1, 1, tzinfo=timezone.utc), tick=False
59 ) as traveller:
60 pf = ProgressFile(file, progress_callback=mock_callback) 1abcdefg
62 pf.read(10) # Should trigger callback with 10 bytes read 1abcdefg
63 traveller.shift(0.1) 1abcdefg
64 pf.read(10) 1abcdefg
65 traveller.shift(0.5) 1abcdefg
66 pf.read(10) # Should trigger callback with 10 + 10 + 10 = 30 bytes read 1abcdefg
67 traveller.shift(0.6) 1abcdefg
68 pf.read(10) # Should trigger callback with 30 + 10 = 40 bytes read 1abcdefg
70 mock_callback.assert_has_calls([call(10), call(30), call(40)]) 1abcdefg
73def test_callback_called_on_eof() -> None: 1hijklmn
74 file = _make_file(b"abcd") 1CEGIKMO
75 mock_callback = Mock() 1CEGIKMO
77 pf = ProgressFile(file, progress_callback=mock_callback) 1CEGIKMO
78 pf.read(3) 1CEGIKMO
79 pf.read(3) 1CEGIKMO
80 mock_callback.assert_has_calls([call(3), call(4)]) 1CEGIKMO
83def test_name_property() -> None: 1hijklmn
84 file = _make_file(name="test.tar.gz") 1XYZ0123
85 pf = ProgressFile(file, progress_callback=lambda _: None) 1XYZ0123
87 assert pf.name == "test.tar.gz" 1XYZ0123
90def test_callback_uses_current_file_position_after_seek() -> None: 1hijklmn
91 file = _make_file(b"abcde") 1prtvxzB
92 mock_callback = Mock() 1prtvxzB
94 pf = ProgressFile(file, progress_callback=mock_callback) 1prtvxzB
96 pf.read(3) 1prtvxzB
98 # Imitate retrying
99 pf.seek(0) 1prtvxzB
100 pf.read(3) 1prtvxzB
102 pf.read(3) 1prtvxzB
104 mock_callback.assert_has_calls([call(3), call(5)]) 1prtvxzB