Add public repository interfaces and subclassable adapter CRUD API.
Define split JSON and object repository ABCs, promote adapter methods to public CRUD, add example domain repositories, modernize interface stubs, and make the package installable for tests. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
co-authored by
Cursor
parent
f4280f15c1
commit
e98fd3b90d
@@ -1,6 +1,3 @@
|
||||
# pylint: disable=protected-access
|
||||
# The above line disables pylint's protected member access warnings for this file,
|
||||
# allowing tests to access MinioAdapter's internal methods as needed for integration testing.
|
||||
"""Integration tests for the MinioAdapter."""
|
||||
|
||||
from collections.abc import Generator
|
||||
@@ -13,6 +10,7 @@ import os
|
||||
import logging
|
||||
from minio import S3Error
|
||||
from python_repositories.adapters.minio_adapter import MinioAdapter
|
||||
from python_repositories.interfaces import ObjectRepositoryInterface
|
||||
|
||||
|
||||
def same_data(
|
||||
@@ -103,7 +101,7 @@ def clear_minio(
|
||||
|
||||
def test_should_adhere_to_interface() -> None:
|
||||
"""Test that the MinioAdapter adheres to the expected interface."""
|
||||
# Instantiation fails if interface not adhered to
|
||||
assert issubclass(MinioAdapter, ObjectRepositoryInterface)
|
||||
_ = MinioAdapter()
|
||||
|
||||
|
||||
@@ -187,7 +185,7 @@ def test_should_get_data(
|
||||
# Arrange
|
||||
object_name, expected_data = data_in_minio
|
||||
# Act
|
||||
received_data = minio_adapter._get(object_name)
|
||||
received_data = minio_adapter.get(object_name)
|
||||
# Assert
|
||||
assert received_data is not None
|
||||
assert same_data(expected_data, received_data)
|
||||
@@ -200,7 +198,7 @@ def test_should_get_none_for_nonexistent_object(
|
||||
# Arrange
|
||||
object_name = "nonexistent_object"
|
||||
# Act
|
||||
received_data = minio_adapter._get(object_name)
|
||||
received_data = minio_adapter.get(object_name)
|
||||
# Assert
|
||||
assert received_data is None
|
||||
|
||||
@@ -214,7 +212,7 @@ def test_should_raise_value_error_on_invalid_get_object_name(
|
||||
# Act & Assert
|
||||
for object_name in invalid_object_names:
|
||||
with pytest.raises(ValueError):
|
||||
minio_adapter._get(object_name) # type: ignore
|
||||
minio_adapter.get(object_name) # type: ignore
|
||||
|
||||
|
||||
def test_should_raise_connection_error_on_get_when_not_connected(
|
||||
@@ -225,7 +223,7 @@ def test_should_raise_connection_error_on_get_when_not_connected(
|
||||
adapter = MinioAdapter() # not connected
|
||||
# Act & Assert
|
||||
with pytest.raises(ConnectionError):
|
||||
adapter._get("some_object")
|
||||
adapter.get("some_object")
|
||||
|
||||
|
||||
def test_should_log_warning_when_getting_nonexistent_object(
|
||||
@@ -249,7 +247,7 @@ def test_should_log_warning_when_getting_nonexistent_object(
|
||||
object_name = "missing-object"
|
||||
# Act
|
||||
with caplog.at_level("WARNING"):
|
||||
result = adapter._get(object_name)
|
||||
result = adapter.get(object_name)
|
||||
# Assert
|
||||
assert result is None
|
||||
assert (
|
||||
@@ -280,7 +278,7 @@ def test_should_log_error_when_getting_with_s3error_other_than_no_such_key(
|
||||
object_name = "missing-object"
|
||||
# Act
|
||||
with caplog.at_level("ERROR"):
|
||||
result = adapter._get(object_name)
|
||||
result = adapter.get(object_name)
|
||||
# Assert
|
||||
assert result is None
|
||||
assert repr(other_s3error) in caplog.text
|
||||
@@ -299,7 +297,7 @@ def test_should_log_error_when_getting_with_general_exception(
|
||||
object_name = "missing-object"
|
||||
# Act
|
||||
with caplog.at_level("ERROR"):
|
||||
result = adapter._get(object_name)
|
||||
result = adapter.get(object_name)
|
||||
# Assert
|
||||
assert result is None
|
||||
assert repr(general_exception) in caplog.text
|
||||
@@ -312,12 +310,12 @@ def test_should_put_data(
|
||||
"""Test that the MinioAdapter can put data into a bucket."""
|
||||
# Arrange
|
||||
object_name = "new_test_object"
|
||||
received_data = minio_adapter._get(object_name)
|
||||
received_data = minio_adapter.get(object_name)
|
||||
assert received_data is None # ensure object does not exist yet
|
||||
# Act
|
||||
minio_adapter._put(object_name, data)
|
||||
minio_adapter.put(object_name, data)
|
||||
# Assert
|
||||
received_data = minio_adapter._get(object_name)
|
||||
received_data = minio_adapter.get(object_name)
|
||||
assert received_data is not None
|
||||
assert same_data(data, received_data)
|
||||
# Cleanup
|
||||
@@ -333,13 +331,13 @@ def test_should_update_data(
|
||||
# Arrange
|
||||
object_name, _ = data_in_minio
|
||||
new_data = BytesIO(random.randbytes(2**21)) # 2 MiB
|
||||
received_data = minio_adapter._get(object_name)
|
||||
received_data = minio_adapter.get(object_name)
|
||||
assert received_data is not None
|
||||
assert not same_data(received_data, new_data)
|
||||
# Act
|
||||
minio_adapter._put(object_name, new_data)
|
||||
minio_adapter.put(object_name, new_data)
|
||||
# Assert
|
||||
received_data = minio_adapter._get(object_name)
|
||||
received_data = minio_adapter.get(object_name)
|
||||
assert received_data is not None
|
||||
assert same_data(new_data, received_data)
|
||||
|
||||
@@ -354,7 +352,7 @@ def test_should_raise_value_error_on_invalid_put_object_name(
|
||||
# Act & Assert
|
||||
for object_name in invalid_object_names:
|
||||
with pytest.raises(ValueError):
|
||||
minio_adapter._put(object_name, data) # type: ignore
|
||||
minio_adapter.put(object_name, data) # type: ignore
|
||||
|
||||
|
||||
def test_should_raise_value_error_on_invalid_put_data(
|
||||
@@ -367,7 +365,7 @@ def test_should_raise_value_error_on_invalid_put_data(
|
||||
# Act & Assert
|
||||
for data in invalid_data:
|
||||
with pytest.raises(ValueError):
|
||||
minio_adapter._put(object_name, data) # type: ignore
|
||||
minio_adapter.put(object_name, data) # type: ignore
|
||||
|
||||
|
||||
def test_should_raise_value_error_on_invalid_put_content_type(
|
||||
@@ -381,7 +379,7 @@ def test_should_raise_value_error_on_invalid_put_content_type(
|
||||
# Act & Assert
|
||||
for content_type in invalid_content_types:
|
||||
with pytest.raises(ValueError):
|
||||
minio_adapter._put(object_name, data, content_type) # type: ignore
|
||||
minio_adapter.put(object_name, data, content_type) # type: ignore
|
||||
|
||||
|
||||
def test_should_raise_connection_error_on_put_when_not_connected(
|
||||
@@ -393,7 +391,7 @@ def test_should_raise_connection_error_on_put_when_not_connected(
|
||||
adapter = MinioAdapter() # not connected
|
||||
# Act & Assert
|
||||
with pytest.raises(ConnectionError):
|
||||
adapter._put("some_object", data)
|
||||
adapter.put("some_object", data)
|
||||
|
||||
|
||||
def test_should_delete_object(
|
||||
@@ -403,12 +401,12 @@ def test_should_delete_object(
|
||||
"""Test that the MinioAdapter can delete an object from a bucket."""
|
||||
# Arrange
|
||||
object_name, _ = data_in_minio
|
||||
received_data = minio_adapter._get(object_name)
|
||||
received_data = minio_adapter.get(object_name)
|
||||
assert received_data is not None # ensure object exists
|
||||
# Act
|
||||
minio_adapter._delete(object_name)
|
||||
minio_adapter.delete(object_name)
|
||||
# Assert
|
||||
received_data = minio_adapter._get(object_name)
|
||||
received_data = minio_adapter.get(object_name)
|
||||
assert received_data is None
|
||||
|
||||
|
||||
@@ -421,7 +419,7 @@ def test_should_raise_value_error_on_invalid_delete_object_name(
|
||||
# Act & Assert
|
||||
for object_name in invalid_object_names:
|
||||
with pytest.raises(ValueError):
|
||||
minio_adapter._delete(object_name) # type: ignore
|
||||
minio_adapter.delete(object_name) # type: ignore
|
||||
|
||||
|
||||
def test_should_raise_connection_error_on_delete_when_not_connected(
|
||||
@@ -432,7 +430,7 @@ def test_should_raise_connection_error_on_delete_when_not_connected(
|
||||
adapter = MinioAdapter() # not connected
|
||||
# Act & Assert
|
||||
with pytest.raises(ConnectionError):
|
||||
adapter._delete("some_object")
|
||||
adapter.delete("some_object")
|
||||
|
||||
|
||||
def test_should_list_objects(
|
||||
@@ -444,9 +442,9 @@ def test_should_list_objects(
|
||||
object_name, _ = data_in_minio
|
||||
new_data = BytesIO(random.randbytes(2**21)) # 2 MiB
|
||||
new_data_name = "another_test_object"
|
||||
minio_adapter._put(new_data_name, new_data)
|
||||
minio_adapter.put(new_data_name, new_data)
|
||||
# Act
|
||||
objects = minio_adapter._list_objects()
|
||||
objects = minio_adapter.list_objects()
|
||||
# Assert
|
||||
assert isinstance(objects, list)
|
||||
assert len(objects) == 2
|
||||
@@ -463,10 +461,10 @@ def test_should_list_objects_with_prefix(
|
||||
object_name, _ = data_in_minio
|
||||
new_data = BytesIO(random.randbytes(2**21)) # 2 MiB
|
||||
new_data_name = "prefix_test_object"
|
||||
minio_adapter._put(new_data_name, new_data)
|
||||
minio_adapter.put(new_data_name, new_data)
|
||||
prefix = "prefix_"
|
||||
# Act
|
||||
objects = minio_adapter._list_objects(prefix)
|
||||
objects = minio_adapter.list_objects(prefix)
|
||||
# Assert
|
||||
assert isinstance(objects, list)
|
||||
assert len(objects) == 1
|
||||
@@ -483,7 +481,7 @@ def test_should_raise_value_error_on_invalid_list_objects_prefix(
|
||||
# Act & Assert
|
||||
for prefix in invalid_prefixes:
|
||||
with pytest.raises(ValueError):
|
||||
minio_adapter._list_objects(prefix) # type: ignore
|
||||
minio_adapter.list_objects(prefix) # type: ignore
|
||||
|
||||
|
||||
def test_should_raise_connection_error_on_list_objects_when_not_connected(
|
||||
@@ -494,7 +492,7 @@ def test_should_raise_connection_error_on_list_objects_when_not_connected(
|
||||
adapter = MinioAdapter() # not connected
|
||||
# Act & Assert
|
||||
with pytest.raises(ConnectionError):
|
||||
adapter._list_objects()
|
||||
adapter.list_objects()
|
||||
|
||||
|
||||
# allows local debugging by running file as script
|
||||
|
||||
Reference in New Issue
Block a user