Files
govoplan-files/tests/test_storage_backends.py

79 lines
3.1 KiB
Python

from __future__ import annotations
import io
import unittest
from unittest.mock import MagicMock, PropertyMock, patch
from govoplan_files.backend.storage.backends import S3StorageBackend, StorageBackendError
def _backend() -> S3StorageBackend:
return S3StorageBackend(
bucket="files",
endpoint_url="https://objects.example.test",
region_name="test",
access_key_id="access",
secret_access_key="secret",
)
class S3StorageBackendTests(unittest.TestCase):
def test_sdk_transport_fails_closed_in_public_and_private_modes(self) -> None:
for allow_private, address in ((False, "93.184.216.34"), (True, "10.0.0.5")):
with self.subTest(allow_private=allow_private), patch.dict(
"os.environ",
{
"APP_ENV": "production",
"GOVOPLAN_CONNECTOR_ALLOW_PRIVATE_NETWORKS": str(allow_private).lower(),
},
), patch(
"govoplan_core.security.outbound_http.socket.getaddrinfo",
return_value=[(2, 1, 6, "", (address, 443))],
), self.assertRaisesRegex(StorageBackendError, "until that transport supports.*DNS/IP pinning"):
_backend().client
def test_get_bytes_rejects_declared_oversize_object_without_reading(self) -> None:
body = MagicMock()
client = MagicMock()
client.get_object.return_value = {"ContentLength": 6, "Body": body}
with patch.dict("os.environ", {"GOVOPLAN_CONNECTOR_MAX_FILE_TRANSFER_BYTES": "5"}), patch.object(
S3StorageBackend,
"client",
new_callable=PropertyMock,
return_value=client,
), self.assertRaisesRegex(StorageBackendError, "deployment limit"):
_backend().get_bytes("large.bin")
body.read.assert_not_called()
body.close.assert_called_once_with()
def test_iter_bytes_rejects_undeclared_oversize_object(self) -> None:
client = MagicMock()
client.get_object.return_value = {"Body": io.BytesIO(b"123456")}
with patch.dict("os.environ", {"GOVOPLAN_CONNECTOR_MAX_FILE_TRANSFER_BYTES": "5"}), patch.object(
S3StorageBackend,
"client",
new_callable=PropertyMock,
return_value=client,
), self.assertRaisesRegex(StorageBackendError, "deployment limit"):
list(_backend().iter_bytes("large.bin", chunk_size=3))
def test_iter_bytes_closes_streaming_body_when_consumer_stops_early(self) -> None:
body = MagicMock()
body.read.side_effect = (b"123", b"456", b"")
client = MagicMock()
client.get_object.return_value = {"ContentLength": 6, "Body": body}
with patch.dict("os.environ", {"GOVOPLAN_CONNECTOR_MAX_FILE_TRANSFER_BYTES": "10"}), patch.object(
S3StorageBackend,
"client",
new_callable=PropertyMock,
return_value=client,
):
chunks = _backend().iter_bytes("object.bin", chunk_size=3)
self.assertEqual(b"123", next(chunks))
chunks.close()
body.close.assert_called_once_with()
if __name__ == "__main__":
unittest.main()