|
15 | 15 | import unittest.mock as mock |
16 | 16 | from unittest.mock import AsyncMock, MagicMock |
17 | 17 | import pytest |
| 18 | +import grpc |
| 19 | + |
18 | 20 |
|
19 | 21 | from google.cloud.storage.asyncio.async_write_object_stream import ( |
20 | 22 | _AsyncWriteObjectStream, |
@@ -194,11 +196,57 @@ async def test_close_success(self, mock_client): |
194 | 196 | stream = _AsyncWriteObjectStream(mock_client, BUCKET, OBJECT) |
195 | 197 | stream._is_stream_open = True |
196 | 198 | stream.socket_like_rpc = AsyncMock() |
| 199 | + |
| 200 | + stream.socket_like_rpc.send = AsyncMock() |
| 201 | + first_resp = _storage_v2.BidiWriteObjectResponse(persisted_size=100) |
| 202 | + stream.socket_like_rpc.recv = AsyncMock(side_effect=[first_resp, grpc.aio.EOF]) |
197 | 203 | stream.socket_like_rpc.close = AsyncMock() |
198 | 204 |
|
199 | 205 | await stream.close() |
200 | 206 | stream.socket_like_rpc.close.assert_awaited_once() |
201 | 207 | assert not stream.is_stream_open |
| 208 | + assert stream.persisted_size == 100 |
| 209 | + |
| 210 | + @pytest.mark.asyncio |
| 211 | + async def test_close_with_persisted_size_then_eof(self, mock_client): |
| 212 | + """Test close when first recv has persisted_size, second is EOF.""" |
| 213 | + stream = _AsyncWriteObjectStream(mock_client, BUCKET, OBJECT) |
| 214 | + stream._is_stream_open = True |
| 215 | + stream.socket_like_rpc = AsyncMock() |
| 216 | + |
| 217 | + # First response has persisted_size (NOT EOF, intermediate) |
| 218 | + persisted_resp = _storage_v2.BidiWriteObjectResponse(persisted_size=500) |
| 219 | + # Second response is EOF (None) |
| 220 | + eof_resp = grpc.aio.EOF |
| 221 | + |
| 222 | + stream.socket_like_rpc.send = AsyncMock() |
| 223 | + stream.socket_like_rpc.recv = AsyncMock(side_effect=[persisted_resp, eof_resp]) |
| 224 | + stream.socket_like_rpc.close = AsyncMock() |
| 225 | + |
| 226 | + await stream.close() |
| 227 | + |
| 228 | + # Verify two recv calls: first has persisted_size (NOT EOF), so read second (EOF) |
| 229 | + assert stream.socket_like_rpc.recv.await_count == 2 |
| 230 | + assert stream.persisted_size == 500 |
| 231 | + assert not stream.is_stream_open |
| 232 | + |
| 233 | + @pytest.mark.asyncio |
| 234 | + async def test_close_with_grpc_aio_eof_response(self, mock_client): |
| 235 | + """Test close when first recv is grpc.aio.EOF sentinel.""" |
| 236 | + stream = _AsyncWriteObjectStream(mock_client, BUCKET, OBJECT) |
| 237 | + stream._is_stream_open = True |
| 238 | + stream.socket_like_rpc = AsyncMock() |
| 239 | + |
| 240 | + # First recv returns grpc.aio.EOF (explicit sentinel from finalize) |
| 241 | + stream.socket_like_rpc.send = AsyncMock() |
| 242 | + stream.socket_like_rpc.recv = AsyncMock(return_value=grpc.aio.EOF) |
| 243 | + stream.socket_like_rpc.close = AsyncMock() |
| 244 | + |
| 245 | + await stream.close() |
| 246 | + |
| 247 | + # Verify only one recv call (grpc.aio.EOF=EOF, so don't read second) |
| 248 | + assert stream.socket_like_rpc.recv.await_count == 1 |
| 249 | + assert not stream.is_stream_open |
202 | 250 |
|
203 | 251 | @pytest.mark.asyncio |
204 | 252 | async def test_methods_require_open_raises(self, mock_client): |
|
0 commit comments