Skip to content

Commit

Permalink
refactor: use 'Client._list_resource' in 'Client.list_blobs'
Browse files Browse the repository at this point in the history
Also, adjust tests for 'Bucket.list_blobs' not to depend on anything but
calling 'Client.list_blobs'.

Toward #38
  • Loading branch information
tseaver committed Jun 8, 2021
1 parent 4d0cb8b commit 0352fdc
Show file tree
Hide file tree
Showing 3 changed files with 193 additions and 153 deletions.
11 changes: 3 additions & 8 deletions google/cloud/storage/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
153 changes: 92 additions & 61 deletions tests/unit/test_bucket.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
182 changes: 98 additions & 84 deletions tests/unit/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down

0 comments on commit 0352fdc

Please sign in to comment.