diff --git a/maxapi/connection/base.py b/maxapi/connection/base.py index 7324f58..cf496a5 100644 --- a/maxapi/connection/base.py +++ b/maxapi/connection/base.py @@ -234,13 +234,15 @@ async def upload_file(self, url: str, path: str, type: UploadType) -> str: session = bot.session if session is not None and not session.closed: - response = await session.post(url=url, data=form) - return await response.text() + async with session.post(url=url, data=form) as response: + return await response.text() else: - async with ClientSession( - timeout=bot.default_connection.timeout - ) as temp_session: - response = await temp_session.post(url=url, data=form) + async with ( + ClientSession( + timeout=bot.default_connection.timeout + ) as temp_session, + temp_session.post(url=url, data=form) as response, + ): return await response.text() async def upload_file_buffer( @@ -285,13 +287,15 @@ async def upload_file_buffer( session = bot.session if session is not None and not session.closed: - response = await session.post(url=url, data=form) - return await response.text() + async with session.post(url=url, data=form) as response: + return await response.text() else: - async with ClientSession( - timeout=bot.default_connection.timeout - ) as temp_session: - response = await temp_session.post(url=url, data=form) + async with ( + ClientSession( + timeout=bot.default_connection.timeout + ) as temp_session, + temp_session.post(url=url, data=form) as response, + ): return await response.text() async def download_file( diff --git a/tests/test_coverage_gaps.py b/tests/test_coverage_gaps.py index 5b77e89..65f928c 100644 --- a/tests/test_coverage_gaps.py +++ b/tests/test_coverage_gaps.py @@ -502,8 +502,12 @@ async def test_upload_file_uses_temp_session_when_session_is_none( mock_response = AsyncMock() mock_response.text = AsyncMock(return_value='{"token":"abc"}') + mock_cm = AsyncMock() + mock_cm.__aenter__.return_value = mock_response + mock_cm.__aexit__.return_value = False + mock_session_instance = AsyncMock() - mock_session_instance.post = AsyncMock(return_value=mock_response) + mock_session_instance.post = Mock(return_value=mock_cm) mock_session_instance.__aenter__ = AsyncMock( return_value=mock_session_instance ) @@ -538,9 +542,13 @@ async def test_upload_file_buffer_mimetypes_guess_extension( mock_response = AsyncMock() mock_response.text = AsyncMock(return_value='{"token":"xyz"}') + mock_cm_buf = AsyncMock() + mock_cm_buf.__aenter__.return_value = mock_response + mock_cm_buf.__aexit__.return_value = False + bot.session = MagicMock() bot.session.closed = False - bot.session.post = AsyncMock(return_value=mock_response) + bot.session.post = Mock(return_value=mock_cm_buf) # Подменяем puremagic, чтобы вернуть распознаваемый MIME-матч, # и mimetypes.guess_extension — чтобы вернуть реальное расширение. @@ -570,3 +578,46 @@ def _fake_getitem(self_m, idx): # guess_extension was called (the covered line) mock_ge.assert_called_once_with("image/png") assert result == '{"token":"xyz"}' + + async def test_upload_file_buffer_uses_temp_session_when_session_is_none( + self, bot + ): + """upload_file_buffer falls back to a new ClientSession + when bot.session=None.""" + from maxapi.connection.base import BaseConnection + from maxapi.enums.upload_type import UploadType + + conn = BaseConnection() + conn.bot = bot + bot.session = None # force the else-branch + + some_buffer = b"\x00" * 32 + + mock_response = AsyncMock() + mock_response.text = AsyncMock(return_value='{"token":"buf"}') + + mock_cm = AsyncMock() + mock_cm.__aenter__.return_value = mock_response + mock_cm.__aexit__.return_value = False + + mock_session_instance = AsyncMock() + mock_session_instance.post = Mock(return_value=mock_cm) + mock_session_instance.__aenter__ = AsyncMock( + return_value=mock_session_instance + ) + mock_session_instance.__aexit__ = AsyncMock(return_value=False) + + with patch( + "maxapi.connection.base.ClientSession", + return_value=mock_session_instance, + ): + result = await conn.upload_file_buffer( + filename="clip", + url="https://upload.example.com", + buffer=some_buffer, + type=UploadType.VIDEO, + ) + + assert result == '{"token":"buf"}' + mock_session_instance.post.assert_called_once() + mock_cm.__aenter__.assert_called_once() diff --git a/tests/test_upload_file.py b/tests/test_upload_file.py index 8312300..b013c90 100644 --- a/tests/test_upload_file.py +++ b/tests/test_upload_file.py @@ -31,9 +31,13 @@ async def test_known_extension_uses_guessed_mime(self, tmp_path): mock_response = AsyncMock() mock_response.text = AsyncMock(return_value='{"token":"t"}') + mock_cm = AsyncMock() + mock_cm.__aenter__.return_value = mock_response + mock_cm.__aexit__.return_value = False + mock_session = AsyncMock(spec=ClientSession) mock_session.closed = False - mock_session.post = AsyncMock(return_value=mock_response) + mock_session.post = Mock(return_value=mock_cm) conn, _bot = _make_connection_with_bot(session=mock_session) @@ -43,7 +47,7 @@ async def test_known_extension_uses_guessed_mime(self, tmp_path): type=UploadType.IMAGE, ) - mock_session.post.assert_awaited_once() + mock_session.post.assert_called_once() @pytest.mark.asyncio async def test_unknown_extension_falls_back_to_type_wildcard( @@ -56,9 +60,13 @@ async def test_unknown_extension_falls_back_to_type_wildcard( mock_response = AsyncMock() mock_response.text = AsyncMock(return_value='{"token":"t"}') + mock_cm = AsyncMock() + mock_cm.__aenter__.return_value = mock_response + mock_cm.__aexit__.return_value = False + mock_session = AsyncMock(spec=ClientSession) mock_session.closed = False - mock_session.post = AsyncMock(return_value=mock_response) + mock_session.post = Mock(return_value=mock_cm) conn, _bot = _make_connection_with_bot(session=mock_session) @@ -72,7 +80,7 @@ async def test_unknown_extension_falls_back_to_type_wildcard( type=UploadType.FILE, ) - mock_session.post.assert_awaited_once() + mock_session.post.assert_called_once() class TestUploadFileTempSession: @@ -90,8 +98,12 @@ async def test_temp_session_with_timeout_when_no_session(self, tmp_path): conn, bot = _make_connection_with_bot(session=None) expected_timeout = bot.default_connection.timeout + mock_cm = AsyncMock() + mock_cm.__aenter__.return_value = mock_response + mock_cm.__aexit__.return_value = False + mock_temp_session = AsyncMock() - mock_temp_session.post = AsyncMock(return_value=mock_response) + mock_temp_session.post = Mock(return_value=mock_cm) with patch( "maxapi.connection.base.ClientSession", @@ -107,7 +119,7 @@ async def test_temp_session_with_timeout_when_no_session(self, tmp_path): ) mock_cs_cls.assert_called_once_with(timeout=expected_timeout) - mock_temp_session.post.assert_awaited_once() + mock_temp_session.post.assert_called_once() @pytest.mark.asyncio async def test_temp_session_with_timeout_when_session_closed( @@ -126,8 +138,12 @@ async def test_temp_session_with_timeout_when_session_closed( conn, bot = _make_connection_with_bot(session=closed_session) expected_timeout = bot.default_connection.timeout + mock_cm = AsyncMock() + mock_cm.__aenter__.return_value = mock_response + mock_cm.__aexit__.return_value = False + mock_temp_session = AsyncMock() - mock_temp_session.post = AsyncMock(return_value=mock_response) + mock_temp_session.post = Mock(return_value=mock_cm) with patch( "maxapi.connection.base.ClientSession", @@ -153,9 +169,13 @@ async def test_uses_existing_session_when_open(self, tmp_path): mock_response = AsyncMock() mock_response.text = AsyncMock(return_value='{"token":"t"}') + mock_cm = AsyncMock() + mock_cm.__aenter__.return_value = mock_response + mock_cm.__aexit__.return_value = False + mock_session = AsyncMock(spec=ClientSession) mock_session.closed = False - mock_session.post = AsyncMock(return_value=mock_response) + mock_session.post = Mock(return_value=mock_cm) conn, _bot = _make_connection_with_bot(session=mock_session) @@ -169,4 +189,4 @@ async def test_uses_existing_session_when_open(self, tmp_path): ) mock_cs_cls.assert_not_called() - mock_session.post.assert_awaited_once() + mock_session.post.assert_called_once()