added infrastructure code
Code Quality Pipeline / code-quality (pull_request) Failing after 1m19s
Test Python Package / test (pull_request) Failing after 50s

This commit is contained in:
Brian Bjarke Jensen
2025-09-18 12:13:39 +02:00
parent 9b4f0daf58
commit 0ba860b892
34 changed files with 3390 additions and 1 deletions
+128
View File
@@ -0,0 +1,128 @@
"""Unit tests for AnnotationRepository class."""
import unittest
from unittest.mock import patch, MagicMock, _patch_dict
from uuid import UUID
from data_store.repositories.annotation_repository import AnnotationRepository
from data_store.dto import (
Annotation,
DistanceEnum,
AngleEnum,
PointOfViewEnum,
ContactEnum,
)
class TestAnnotationRepository(unittest.TestCase):
"""Unit tests for AnnotationRepository class."""
patcher: _patch_dict
repo: AnnotationRepository
job_id: UUID
bad_job_id: str
annotation: Annotation
bad_annotation: dict
@classmethod
def setUpClass(cls) -> None:
"""Set up test case with a mocked MinioAdapter."""
# Patch environment variables for MinioAdapter
cls.patcher = patch.dict(
"os.environ",
{
"MINIO_ENDPOINT": "localhost:9000",
"MINIO_ACCESS_KEY": "minioadmin",
"MINIO_SECRET_KEY": "minioadmin",
"MINIO_BUCKET": "test-bucket",
},
)
cls.patcher.start()
# Prepare AnnotationRepository
cls.repo = AnnotationRepository()
cls.repo._get = MagicMock() # type: ignore[method-assign]
cls.repo._put = MagicMock() # type: ignore[method-assign]
cls.repo._delete = MagicMock() # type: ignore[method-assign]
# Prepare other test variables
cls.job_id = UUID("d87022f8-4169-4d69-8512-bbd65cc1cb23")
cls.bad_job_id = "not-a-uuid"
cls.annotation = Annotation(
distance=DistanceEnum.CLOSE,
angle=AngleEnum.HIGH,
point_of_view=PointOfViewEnum.FRONTAL,
contact=ContactEnum.OFFER,
)
cls.bad_annotation = {"not_an_annotation": "irrelevant value"}
@classmethod
def tearDownClass(cls) -> None:
# Stop patching
cls.patcher.stop()
def setUp(self) -> None:
"""Set up each test with a fresh AnnotationRepository instance."""
self.repo._get.reset_mock() # type: ignore[attr-defined]
self.repo._put.reset_mock() # type: ignore[attr-defined]
self.repo._delete.reset_mock() # type: ignore[attr-defined]
def test_should_adhere_to_interface(self) -> None:
"""Test that AnnotationRepository adheres to AnnotationRepositoryInterface."""
# Instantiation fails if interface not adhered to
_ = AnnotationRepository()
def test_should_have_encoding_set(self) -> None:
"""Test that AnnotationRepository has encoding when instantiated."""
self.assertTrue(hasattr(self.repo, "encoding"))
def test_should_have_data_format_set(self) -> None:
"""Test that AnnotationRepository has data_format when instantiated."""
self.assertTrue(hasattr(self.repo, "data_format"))
def test_should_have_folder_name_set(self) -> None:
"""Test that AnnotationRepository has folder_name when instantiated."""
self.assertTrue(hasattr(self.repo, "folder_name"))
def test_object_name_invalid_job_id_raises_value_error(self) -> None:
"""Test that _object_name() raises ValueError for invalid job_id."""
with self.assertRaises(ValueError):
_ = self.repo._object_name(self.bad_job_id) # type: ignore
def test_get_invalid_job_id_raises_value_error(self) -> None:
"""Test that get() raises ValueError for invalid job_id."""
with self.assertRaises(ValueError):
self.repo.get(self.bad_job_id) # type: ignore
def test_get_data_that_cannot_be_converted_returns_none(self) -> None:
"""Test that get() returns None if retrieved data cannot be converted to Annotation."""
# Arrange
bad_data = b'{"not":"valid annotation data"}'
mock_buffer = MagicMock()
mock_buffer.read.return_value = bad_data
self.repo._get.return_value = mock_buffer # type: ignore[attr-defined]
# Act
result = self.repo.get(self.job_id)
# Assert
self.assertIsNone(result)
self.repo._get.assert_called_once_with( # type: ignore[attr-defined]
f"{self.repo.folder_name}/{self.job_id}.{self.repo.data_format}"
)
def test_put_invalid_job_id_raises_value_error(self) -> None:
"""Test that put() raises ValueError for invalid job_id."""
with self.assertRaises(ValueError):
self.repo.put(self.annotation, self.bad_job_id) # type: ignore
def test_put_invalid_annotation_raises_value_error(self) -> None:
"""Test that put() raises ValueError for invalid annotation."""
with self.assertRaises(ValueError):
self.repo.put(self.bad_annotation, self.job_id) # type: ignore
def test_delete_invalid_job_id_raises_value_error(self) -> None:
"""Test that delete() raises ValueError for invalid job_id."""
with self.assertRaises(ValueError):
self.repo.delete(self.bad_job_id) # type: ignore
# Allows local debugging by running file as script
if __name__ == "__main__":
unittest.main()
+98
View File
@@ -0,0 +1,98 @@
"""Unit tests for ImageRepository class."""
import unittest
from unittest.mock import patch, MagicMock, _patch_dict
from uuid import UUID
from PIL import Image
from data_store.repositories.image_repository import ImageRepository
class TestImageRepository(unittest.TestCase):
"""Unit tests for ImageRepository class."""
patcher: _patch_dict
repo: ImageRepository
image: Image.Image
bad_image: str
image_id: UUID
bad_image_id: str
@classmethod
def setUpClass(cls) -> None:
"""Set up test case with a mocked MinioAdapter."""
# Patch environment variables for MinioAdapter
cls.patcher = patch.dict(
"os.environ",
{
"MINIO_ENDPOINT": "localhost:9000",
"MINIO_ACCESS_KEY": "minioadmin",
"MINIO_SECRET_KEY": "minioadmin",
"MINIO_BUCKET": "test-bucket",
},
)
cls.patcher.start()
# Prepare ImageRepository with mocked MinioAdapter
cls.repo = ImageRepository()
cls.repo._get = MagicMock(return_value=None) # type: ignore[method-assign]
cls.repo._put = MagicMock(return_value=None) # type: ignore[method-assign]
cls.repo._delete = MagicMock(return_value=None) # type: ignore[method-assign]
# Prepare other test variables
cls.image = Image.new("RGB", (10, 10))
cls.image_id = UUID("d87022f8-4169-4d69-8512-bbd65cc1cb23")
cls.bad_image = "not_an_image"
cls.bad_image_id = "not-a-uuid"
@classmethod
def tearDownClass(cls) -> None:
# Stop patching
cls.patcher.stop()
def setUp(self) -> None:
"""Set up each test with a fresh ImageRepository instance."""
self.repo._get.reset_mock() # type: ignore[attr-defined]
self.repo._put.reset_mock() # type: ignore[attr-defined]
self.repo._delete.reset_mock() # type: ignore[attr-defined]
def test_should_adhere_to_interface(self) -> None:
"""Test that ImageRepository adheres to ImageRepositoryInterface."""
# Instantiation fails if interface not adhered to
_ = ImageRepository()
def test_should_have_image_format_set(self) -> None:
"""Test that ImageRepository has image_format set."""
self.assertTrue(hasattr(self.repo, "image_format"))
def test_should_have_folder_name_set(self) -> None:
"""Test that ImageRepository has folder_name set."""
self.assertTrue(hasattr(self.repo, "folder_name"))
def test_object_name_invalid_image_id_raises_value_error(self) -> None:
"""Test that _object_name() raises ValueError for invalid image_id."""
with self.assertRaises(ValueError):
_ = self.repo._object_name(self.bad_image_id) # type: ignore
def test_get_invalid_image_id_raises_value_error(self) -> None:
"""Test getting an image with invalid image_id."""
with self.assertRaises(ValueError):
self.repo.get(self.bad_image_id) # type: ignore
def test_put_invalid_image_id_raises_value_error(self) -> None:
"""Test putting an image with invalid image_id."""
with self.assertRaises(ValueError):
self.repo.put(self.image, self.bad_image_id) # type: ignore
def test_put_invalid_image_type_raises_value_error(self) -> None:
"""Test putting an invalid image type."""
with self.assertRaises(ValueError):
self.repo.put(self.bad_image, self.bad_image_id) # type: ignore
def test_delete_invalid_image_id_raises_value_error(self) -> None:
"""Test deleting an image with invalid image_id."""
with self.assertRaises(ValueError):
self.repo.delete(self.bad_image_id) # type: ignore
# Allows local debugging by running file as script
if __name__ == "__main__":
unittest.main()
+85
View File
@@ -0,0 +1,85 @@
"""Unit tests for JobRepository class."""
import unittest
from unittest.mock import patch, MagicMock, _patch_dict
from uuid import UUID
from data_store.repositories.job_repository import JobRepository
class TestJobRepository(unittest.TestCase):
"""Unit tests for JobRepository class."""
patcher: _patch_dict
repo: JobRepository
job_id: UUID
bad_job_id: str
@classmethod
def setUpClass(cls) -> None:
"""Set up test case with a mocked MinioAdapter."""
# Patch environment variables for MinioAdapter
cls.patcher = patch.dict(
"os.environ",
{
"MINIO_ENDPOINT": "localhost:9000",
"MINIO_ACCESS_KEY": "minioadmin",
"MINIO_SECRET_KEY": "minioadmin",
"MINIO_BUCKET": "test-bucket",
},
)
cls.patcher.start()
# Prepare JobRepository
cls.repo = JobRepository()
cls.repo._get = MagicMock(return_value=None) # type: ignore[method-assign]
cls.repo._put = MagicMock(return_value=None) # type: ignore[method-assign]
cls.repo._delete = MagicMock(return_value=None) # type: ignore[method-assign]
# Prepare other test variables
cls.job_id = UUID("d87022f8-4169-4d69-8512-bbd65cc1cb23")
cls.bad_job_id = "not-a-uuid"
@classmethod
def tearDownClass(cls) -> None:
# Stop patching
cls.patcher.stop()
def setUp(self) -> None:
"""Set up each test with a fresh JobRepository instance."""
self.repo._get.reset_mock() # type: ignore[attr-defined]
self.repo._put.reset_mock() # type: ignore[attr-defined]
self.repo._delete.reset_mock() # type: ignore[attr-defined]
def test_should_adhere_to_interface(self) -> None:
"""Test that JobRepository adheres to JobRepositoryInterface."""
# Instantiation fails if interface not adhered to
_ = JobRepository()
def test_enter_calls_super_and_returns_self(self) -> None:
"""Test that __enter__ calls super().__enter__() and returns self."""
repo = JobRepository()
with patch(
"python_repositories.adapters.MinioAdapter.__enter__", return_value=None
) as mock_super_enter:
result = repo.__enter__()
mock_super_enter.assert_called_once()
self.assertIs(result, repo)
def test_get_invalid_job_id_raises_value_error(self) -> None:
"""Test that get with invalid job_id raises ValueError."""
with self.assertRaises(ValueError):
self.repo.get(self.bad_job_id) # type: ignore[arg-type]
def test_put_invalid_job_raises_value_error(self) -> None:
"""Test that put with invalid job raises ValueError."""
with self.assertRaises(ValueError):
self.repo.put("not_a_job") # type: ignore[arg-type]
def test_delete_invalid_job_id_raises_value_error(self) -> None:
"""Test that delete with invalid job_id raises ValueError."""
with self.assertRaises(ValueError):
self.repo.delete(self.bad_job_id) # type: ignore[arg-type]
# Allows local debugging by running file as script
if __name__ == "__main__":
unittest.main()