From 4323e8fcc37f447b21ba3b46e1cc84970a83ea5e Mon Sep 17 00:00:00 2001 From: Wouter van Atteveldt Date: Tue, 23 Apr 2024 15:27:51 +1000 Subject: [PATCH 1/2] Changes to (mostly) the bucket interface: - added remove_bucket function - changed return type of list_buckets to Bucket rather than str to conform with regular Minio behaviour (note: somewhat breaking change) - wrap self.object iteration in list_objects in a list to allow modification during iteration --- pytest_minio_mock/plugin.py | 44 ++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/pytest_minio_mock/plugin.py b/pytest_minio_mock/plugin.py index e4efdf2..33bc060 100644 --- a/pytest_minio_mock/plugin.py +++ b/pytest_minio_mock/plugin.py @@ -21,6 +21,7 @@ application interacts correctly with Minio, without the overhead of connecting to an actual Minio server. """ + import copy import datetime import io @@ -32,7 +33,7 @@ import validators from minio import Minio from minio.commonconfig import ENABLED -from minio.datatypes import Object +from minio.datatypes import Object, Bucket from minio.error import S3Error from minio.versioningconfig import OFF from minio.versioningconfig import SUSPENDED @@ -385,6 +386,7 @@ def __init__( self._objects = {} self._location = location self._object_lock = object_lock + self._creation_date = datetime.datetime.now() @property def bucket_name(self): @@ -508,7 +510,8 @@ def list_objects( # bucket_objects = [] seen_prefixes = set() - for object_name, obj in self.objects.items(): + # Note: Wrapped items() in list(.) to allow modification during iteration + for object_name, obj in list(self.objects.items()): if object_name.startswith(prefix) and ( start_after == "" or object_name > start_after ): @@ -1070,10 +1073,7 @@ def list_buckets(self): """ try: self._health_check() - buckets_list = [] - for bucket_name in self.buckets.keys(): - buckets_list.append(bucket_name) - return buckets_list + return [Bucket(name, bucket._creation_date) for (name, bucket) in list(self.buckets.items())] except Exception as e: logging.error(e) raise e @@ -1123,6 +1123,38 @@ def make_bucket(self, bucket_name, location=None, object_lock=False): ) return True + def remove_bucket(self, bucket_name: str): + """ + Remove an empty bucket. + + :param bucket_name: Name of the bucket. + + Example:: + client.remove_bucket("my-bucket") + """ + self._health_check() + if bucket_name not in self.buckets: + raise S3Error( + code="NoSuchBucket", + message="The specified bucket does not exist", + resource=f"/{bucket_name}", + request_id=None, + host_id=None, + response="mocked_response", + bucket_name=bucket_name, + ) + if self.buckets[bucket_name].objects: + raise S3Error( + code="BucketNotEmpty", + message="The bucket you tried to delete is not empty", + resource=f"/{bucket_name}", + request_id=None, + host_id=None, + response="mocked_response", + bucket_name=bucket_name, + ) + del self.buckets[bucket_name] + def set_bucket_versioning(self, bucket_name: str, config: VersioningConfig): """Bucket versioning can be set to ENABLED or SUSPENDED, but not to OFF (filtered out by VersioningConfig itself) From 8b33d2087f65110997335f7444c214ecd2ab4d4c Mon Sep 17 00:00:00 2001 From: Wouter van Atteveldt Date: Fri, 26 Apr 2024 14:26:58 +1000 Subject: [PATCH 2/2] Unit tests: Add test_remove_bucket, adapt test_list_buckets to check return type --- tests/test_minio_mock.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/test_minio_mock.py b/tests/test_minio_mock.py index 8a95ca5..9b934fc 100644 --- a/tests/test_minio_mock.py +++ b/tests/test_minio_mock.py @@ -8,6 +8,7 @@ from minio.versioningconfig import OFF from minio.versioningconfig import SUSPENDED from minio.versioningconfig import VersioningConfig +from minio.datatypes import Bucket from pytest_minio_mock.plugin import MockMinioBucket from pytest_minio_mock.plugin import MockMinioObject @@ -63,6 +64,21 @@ def test_make_bucket(minio_mock): assert client.bucket_exists(bucket_name), "Bucket should exist after creation" +@pytest.mark.UNIT +@pytest.mark.API +def test_remove_bucket(minio_mock): + client = Minio("http://local.host:9000") + original_buckets = client.list_buckets() + n = len(original_buckets) + bucket_name = "new-bucket" + client.make_bucket(bucket_name) + buckets = client.list_buckets() + assert len(buckets) == n + 1 + client.remove_bucket(bucket_name) + buckets = client.list_buckets() + assert buckets == original_buckets + + @pytest.mark.API @pytest.mark.FUNC def test_putting_and_removing_objects_no_versionning(minio_mock): @@ -369,6 +385,8 @@ def test_list_buckets(minio_mock): client.make_bucket(bucket_name) buckets = client.list_buckets() assert len(buckets) == n + 1 + assert "new-bucket" in {b.name for b in buckets} + assert all(isinstance(b, Bucket) for b in buckets) @pytest.mark.REGRESSION