79 lines
3.1 KiB
Python
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()
|