diff --git a/google/cloud/storage/client.py b/google/cloud/storage/client.py index eb9d2f97e..91ca2e4ac 100644 --- a/google/cloud/storage/client.py +++ b/google/cloud/storage/client.py @@ -1239,14 +1239,9 @@ def list_blobs( extra_params["userProject"] = bucket.user_project path = bucket.path + "/o" - api_request = functools.partial( - self._connection.api_request, timeout=timeout, retry=retry - ) - iterator = page_iterator.HTTPIterator( - client=self, - api_request=api_request, - path=path, - item_to_value=_item_to_blob, + iterator = self._list_resource( + path, + _item_to_blob, page_token=page_token, max_results=max_results, extra_params=extra_params, diff --git a/tests/unit/test_bucket.py b/tests/unit/test_bucket.py index 018d753f7..8e0e56f33 100644 --- a/tests/unit/test_bucket.py +++ b/tests/unit/test_bucket.py @@ -902,72 +902,103 @@ def test_get_blob_hit_with_kwargs_w_explicit_client(self): _target_object=blob, ) - def test_list_blobs_defaults(self): - NAME = "name" - connection = _Connection({"items": []}) + def test_list_blobs_w_defaults(self): + name = "name" client = self._make_client() - client._base_connection = connection - bucket = self._make_one(client=client, name=NAME) + client.list_blobs = mock.Mock(spec=[]) + bucket = self._make_one(client=client, name=name) + iterator = bucket.list_blobs() - blobs = list(iterator) - self.assertEqual(blobs, []) - (kw,) = connection._requested - self.assertEqual(kw["method"], "GET") - self.assertEqual(kw["path"], "/b/%s/o" % NAME) - self.assertEqual(kw["query_params"], {"projection": "noAcl"}) - self.assertEqual(kw["timeout"], self._get_default_timeout()) - def test_list_blobs_w_all_arguments_and_user_project(self): - NAME = "name" - USER_PROJECT = "user-project-123" - MAX_RESULTS = 10 - PAGE_TOKEN = "ABCD" - PREFIX = "subfolder" - DELIMITER = "/" - START_OFFSET = "c" - END_OFFSET = "g" - INCLUDE_TRAILING_DELIMITER = True - VERSIONS = True - PROJECTION = "full" - FIELDS = "items/contentLanguage,nextPageToken" - EXPECTED = { - "maxResults": 10, - "pageToken": PAGE_TOKEN, - "prefix": PREFIX, - "delimiter": DELIMITER, - "startOffset": START_OFFSET, - "endOffset": END_OFFSET, - "includeTrailingDelimiter": INCLUDE_TRAILING_DELIMITER, - "versions": VERSIONS, - "projection": PROJECTION, - "fields": FIELDS, - "userProject": USER_PROJECT, - } - connection = _Connection({"items": []}) - client = self._make_client() - client._base_connection = connection - bucket = self._make_one(name=NAME, user_project=USER_PROJECT) + self.assertIs(iterator, client.list_blobs.return_value) + + expected_page_token = None + expected_max_results = None + expected_prefix = None + expected_delimiter = None + expected_start_offset = None + expected_end_offset = None + expected_include_trailing_delimiter = None + expected_versions = None + expected_projection = "noAcl" + expected_fields = None + client.list_blobs.assert_called_once_with( + bucket, + max_results=expected_max_results, + page_token=expected_page_token, + prefix=expected_prefix, + delimiter=expected_delimiter, + start_offset=expected_start_offset, + end_offset=expected_end_offset, + include_trailing_delimiter=expected_include_trailing_delimiter, + versions=expected_versions, + projection=expected_projection, + fields=expected_fields, + timeout=self._get_default_timeout(), + retry=DEFAULT_RETRY, + ) + + def test_list_blobs_w_explicit(self): + name = "name" + max_results = 10 + page_token = "ABCD" + prefix = "subfolder" + delimiter = "/" + start_offset = "c" + end_offset = "g" + include_trailing_delimiter = True + versions = True + projection = "full" + fields = "items/contentLanguage,nextPageToken" + bucket = self._make_one(client=None, name=name) + other_client = self._make_client() + other_client.list_blobs = mock.Mock(spec=[]) + timeout = 42 + retry = mock.Mock(spec=[]) + iterator = bucket.list_blobs( - max_results=MAX_RESULTS, - page_token=PAGE_TOKEN, - prefix=PREFIX, - delimiter=DELIMITER, - start_offset=START_OFFSET, - end_offset=END_OFFSET, - include_trailing_delimiter=INCLUDE_TRAILING_DELIMITER, - versions=VERSIONS, - projection=PROJECTION, - fields=FIELDS, - client=client, - timeout=42, + max_results=max_results, + page_token=page_token, + prefix=prefix, + delimiter=delimiter, + start_offset=start_offset, + end_offset=end_offset, + include_trailing_delimiter=include_trailing_delimiter, + versions=versions, + projection=projection, + fields=fields, + client=other_client, + timeout=timeout, + retry=retry, + ) + + self.assertIs(iterator, other_client.list_blobs.return_value) + + expected_page_token = page_token + expected_max_results = max_results + expected_prefix = prefix + expected_delimiter = delimiter + expected_start_offset = start_offset + expected_end_offset = end_offset + expected_include_trailing_delimiter = include_trailing_delimiter + expected_versions = versions + expected_projection = projection + expected_fields = fields + other_client.list_blobs.assert_called_once_with( + bucket, + max_results=expected_max_results, + page_token=expected_page_token, + prefix=expected_prefix, + delimiter=expected_delimiter, + start_offset=expected_start_offset, + end_offset=expected_end_offset, + include_trailing_delimiter=expected_include_trailing_delimiter, + versions=expected_versions, + projection=expected_projection, + fields=expected_fields, + timeout=timeout, + retry=retry, ) - blobs = list(iterator) - self.assertEqual(blobs, []) - (kw,) = connection._requested - self.assertEqual(kw["method"], "GET") - self.assertEqual(kw["path"], "/b/%s/o" % NAME) - self.assertEqual(kw["query_params"], EXPECTED) - self.assertEqual(kw["timeout"], 42) def test_list_notifications(self): from google.cloud.storage.notification import BucketNotification diff --git a/tests/unit/test_client.py b/tests/unit/test_client.py index a305ddb55..4588f6168 100644 --- a/tests/unit/test_client.py +++ b/tests/unit/test_client.py @@ -1487,98 +1487,112 @@ def test_download_blob_to_file_wo_chunks_w_raw(self): def test_download_blob_to_file_w_chunks_w_raw(self): self._download_blob_to_file_helper(use_chunks=True, raw_download=True) - def test_list_blobs(self): + def test_list_blobs_w_defaults_w_bucket_obj(self): from google.cloud.storage.bucket import Bucket + from google.cloud.storage.bucket import _blobs_page_start + from google.cloud.storage.bucket import _item_to_blob - BUCKET_NAME = "bucket-name" - + project = "PROJECT" + bucket_name = "bucket-name" credentials = _make_credentials() - client = self._make_one(project="PROJECT", credentials=credentials) - connection = _make_connection({"items": []}) - - with mock.patch( - "google.cloud.storage.client.Client._connection", - new_callable=mock.PropertyMock, - ) as client_mock: - client_mock.return_value = connection - - bucket_obj = Bucket(client, BUCKET_NAME) - iterator = client.list_blobs(bucket_obj) - blobs = list(iterator) - - self.assertEqual(blobs, []) - connection.api_request.assert_called_once_with( - method="GET", - path="/b/%s/o" % BUCKET_NAME, - query_params={"projection": "noAcl"}, - timeout=self._get_default_timeout(), - retry=DEFAULT_RETRY, - ) - - def test_list_blobs_w_all_arguments_and_user_project(self): - from google.cloud.storage.bucket import Bucket + client = self._make_one(project=project, credentials=credentials) + client._list_resource = mock.Mock(spec=[]) + bucket = Bucket(client, bucket_name) + + iterator = client.list_blobs(bucket) + + self.assertIs(iterator, client._list_resource.return_value) + self.assertIs(iterator.bucket, bucket) + self.assertEqual(iterator.prefixes, set()) + + expected_path = "/b/{}/o".format(bucket_name) + expected_item_to_value = _item_to_blob + expected_page_token = None + expected_max_results = None + expected_extra_params = {"projection": "noAcl"} + expected_page_start = _blobs_page_start + client._list_resource.assert_called_once_with( + expected_path, + expected_item_to_value, + page_token=expected_page_token, + max_results=expected_max_results, + extra_params=expected_extra_params, + page_start=expected_page_start, + ) - BUCKET_NAME = "name" - USER_PROJECT = "user-project-123" - MAX_RESULTS = 10 - PAGE_TOKEN = "ABCD" - PREFIX = "subfolder" - DELIMITER = "/" - START_OFFSET = "c" - END_OFFSET = "g" - INCLUDE_TRAILING_DELIMITER = True - VERSIONS = True - PROJECTION = "full" - FIELDS = "items/contentLanguage,nextPageToken" - EXPECTED = { - "maxResults": 10, - "pageToken": PAGE_TOKEN, - "prefix": PREFIX, - "delimiter": DELIMITER, - "startOffset": START_OFFSET, - "endOffset": END_OFFSET, - "includeTrailingDelimiter": INCLUDE_TRAILING_DELIMITER, - "versions": VERSIONS, - "projection": PROJECTION, - "fields": FIELDS, - "userProject": USER_PROJECT, - } + def test_list_blobs_w_explicit_w_user_project(self): + from google.cloud.storage.bucket import _blobs_page_start + from google.cloud.storage.bucket import _item_to_blob + project = "PROJECT" + user_project = "user-project-123" + bucket_name = "name" + max_results = 10 + page_token = "ABCD" + prefix = "subfolder" + delimiter = "/" + start_offset = "c" + end_offset = "g" + include_trailing_delimiter = True + versions = True + projection = "full" + fields = "items/contentLanguage,nextPageToken" credentials = _make_credentials() - client = self._make_one(project=USER_PROJECT, credentials=credentials) - connection = _make_connection({"items": []}) + client = self._make_one(project=project, credentials=credentials) + client._list_resource = mock.Mock(spec=[]) + client._bucket_arg_to_bucket = mock.Mock(spec=[]) + bucket = client._bucket_arg_to_bucket.return_value = mock.Mock( + spec=["path", "user_project"], + ) + bucket.path = "/b/{}".format(bucket_name) + bucket.user_project = user_project + timeout = 42 + retry = mock.Mock(spec=[]) - with mock.patch( - "google.cloud.storage.client.Client._connection", - new_callable=mock.PropertyMock, - ) as client_mock: - client_mock.return_value = connection - - bucket = Bucket(client, BUCKET_NAME, user_project=USER_PROJECT) - iterator = client.list_blobs( - bucket_or_name=bucket, - max_results=MAX_RESULTS, - page_token=PAGE_TOKEN, - prefix=PREFIX, - delimiter=DELIMITER, - start_offset=START_OFFSET, - end_offset=END_OFFSET, - include_trailing_delimiter=INCLUDE_TRAILING_DELIMITER, - versions=VERSIONS, - projection=PROJECTION, - fields=FIELDS, - timeout=42, - ) - blobs = list(iterator) + iterator = client.list_blobs( + bucket_or_name=bucket_name, + max_results=max_results, + page_token=page_token, + prefix=prefix, + delimiter=delimiter, + start_offset=start_offset, + end_offset=end_offset, + include_trailing_delimiter=include_trailing_delimiter, + versions=versions, + projection=projection, + fields=fields, + timeout=timeout, + retry=retry, + ) - self.assertEqual(blobs, []) - connection.api_request.assert_called_once_with( - method="GET", - path="/b/%s/o" % BUCKET_NAME, - query_params=EXPECTED, - timeout=42, - retry=DEFAULT_RETRY, - ) + self.assertIs(iterator, client._list_resource.return_value) + self.assertIs(iterator.bucket, bucket) + self.assertEqual(iterator.prefixes, set()) + + expected_path = "/b/{}/o".format(bucket_name) + expected_item_to_value = _item_to_blob + expected_page_token = page_token + expected_max_results = max_results + expected_extra_params = { + "projection": projection, + "prefix": prefix, + "delimiter": delimiter, + "startOffset": start_offset, + "endOffset": end_offset, + "includeTrailingDelimiter": include_trailing_delimiter, + "versions": versions, + "fields": fields, + "userProject": user_project, + } + expected_page_start = _blobs_page_start + client._list_resource.assert_called_once_with( + expected_path, + expected_item_to_value, + page_token=expected_page_token, + max_results=expected_max_results, + extra_params=expected_extra_params, + page_start=expected_page_start, + ) def test_list_buckets_wo_project(self): CREDENTIALS = _make_credentials()