Repository: googleapis/python-storage

Issue:
Unit tests must not depend on environment variables
E.g.,:

```bash
$ env | grep GOOGLE || echo NO
NO
$ nox -re unit-3.9 -- -x
_______________ Test_Blob.test_download_as_byte_w_custom_timeout _______________

self = <tests.unit.test_blob.Test_Blob testMethod=test_download_as_byte_w_custom_timeout>

    def test_download_as_byte_w_custom_timeout(self):
>       self._download_as_bytes_helper(raw_download=False, timeout=9.58)

tests/unit/test_blob.py:1714: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
tests/unit/test_blob.py:1557: in _download_as_bytes_helper
    client = self._make_client()
tests/unit/test_blob.py:59: in _make_client
    return Client(*args, **kw)
google/cloud/storage/client.py:122: in __init__
    super(Client, self).__init__(
.nox/unit-3-9/lib/python3.9/site-packages/google/cloud/client.py:277: in __init__
    _ClientProjectMixin.__init__(self, project=project, credentials=credentials)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <google.cloud.storage.client.Client object at 0x7fb9f31415b0>
project = None, credentials = None

    def __init__(self, project=None, credentials=None):
        # This test duplicates the one from `google.auth.default`, but earlier,
        # for backward compatibility:  we want the environment variable to
        # override any project set on the credentials.  See:
        # https://github.com/googleapis/python-cloud-core/issues/27
        if project is None:
            project = os.getenv(
                environment_vars.PROJECT,
                os.getenv(environment_vars.LEGACY_PROJECT),
            )
    
        # Project set on explicit credentials overrides discovery from
        # SDK / GAE / GCE.
        if project is None and credentials is not None:
            project = getattr(credentials, "project_id", None)
    
        if project is None:
            project = self._determine_default(project)
    
        if project is None:
>           raise EnvironmentError(
                "Project was not passed and could not be "
                "determined from the environment."
            )
E           OSError: Project was not passed and could not be determined from the environment.

.nox/unit-3-9/lib/python3.9/site-packages/google/cloud/client.py:228: OSError
```

Discussion:

Patch:
diff --git a/google/cloud/storage/bucket.py b/google/cloud/storage/bucket.py
index 685d3b5..b79fc12 100644
--- a/google/cloud/storage/bucket.py
+++ b/google/cloud/storage/bucket.py
@@ -3181,7 +3181,7 @@ class Bucket(_PropertyMixin):
                   to attach the signature.
         """
         client = self._require_client(client)
-        credentials = client._base_connection.credentials
+        credentials = client._credentials
         _signing.ensure_signed_credentials(credentials)
 
         if expiration is None:


Test patch:
diff --git a/tests/unit/test_blob.py b/tests/unit/test_blob.py
index 44959f5..3ec0db7 100644
--- a/tests/unit/test_blob.py
+++ b/tests/unit/test_blob.py
@@ -57,7 +57,7 @@ class Test_Blob(unittest.TestCase):
     def _make_client(*args, **kw):
         from google.cloud.storage.client import Client
 
-        return Client(*args, **kw)
+        return mock.create_autospec(Client, instance=True, **kw)
 
     def test_ctor_wo_encryption_key(self):
         BLOB_NAME = "blob-name"
@@ -422,10 +422,10 @@ class Test_Blob(unittest.TestCase):
     def test_generate_signed_url_w_invalid_version(self):
         BLOB_NAME = "blob-name"
         EXPIRATION = "2014-10-16T20:34:37.000Z"
-        connection = _Connection()
-        client = _Client(connection)
+        client = self._make_client()
         bucket = _Bucket(client)
         blob = self._make_one(BLOB_NAME, bucket=bucket)
+
         with self.assertRaises(ValueError):
             blob.generate_signed_url(EXPIRATION, version="nonesuch")
 
@@ -464,8 +464,13 @@ class Test_Blob(unittest.TestCase):
         if expiration is None:
             expiration = datetime.datetime.utcnow().replace(tzinfo=UTC) + delta
 
-        connection = _Connection()
-        client = _Client(connection)
+        if credentials is None:
+            expected_creds = _make_credentials()
+            client = self._make_client(_credentials=expected_creds)
+        else:
+            expected_creds = credentials
+            client = self._make_client(_credentials=object())
+
         bucket = _Bucket(client)
         blob = self._make_one(blob_name, bucket=bucket, encryption_key=encryption_key)
 
@@ -500,11 +505,6 @@ class Test_Blob(unittest.TestCase):
 
         self.assertEqual(signed_uri, signer.return_value)
 
-        if credentials is None:
-            expected_creds = _Connection.credentials
-        else:
-            expected_creds = credentials
-
         encoded_name = blob_name.encode("utf-8")
         quoted_name = parse.quote(encoded_name, safe=b"/~")
 
@@ -784,8 +784,7 @@ class Test_Blob(unittest.TestCase):
 
     def test_delete_wo_generation(self):
         BLOB_NAME = "blob-name"
-        connection = _Connection()  # no requests will be made
-        client = _Client(connection)
+        client = self._make_client()
         bucket = _Bucket(client)
         blob = self._make_one(BLOB_NAME, bucket=bucket)
         bucket._blobs[BLOB_NAME] = 1
@@ -812,8 +811,7 @@ class Test_Blob(unittest.TestCase):
     def test_delete_w_generation(self):
         BLOB_NAME = "blob-name"
         GENERATION = 123456
-        connection = _Connection()  # no requests will be made
-        client = _Client(connection)
+        client = self._make_client()
         bucket = _Bucket(client)
         blob = self._make_one(BLOB_NAME, bucket=bucket, generation=GENERATION)
         bucket._blobs[BLOB_NAME] = 1
@@ -840,8 +838,7 @@ class Test_Blob(unittest.TestCase):
     def test_delete_w_generation_match(self):
         BLOB_NAME = "blob-name"
         GENERATION = 123456
-        connection = _Connection()  # no requests will be made
-        client = _Client(connection)
+        client = self._make_client()
         bucket = _Bucket(client)
         blob = self._make_one(BLOB_NAME, bucket=bucket, generation=GENERATION)
         bucket._blobs[BLOB_NAME] = 1
@@ -1024,6 +1021,99 @@ class Test_Blob(unittest.TestCase):
         response.request = requests.Request("POST", "http://example.com").prepare()
         return response
 
+    def test__extract_headers_from_download_gzipped(self):
+        blob_name = "blob-name"
+        client = mock.Mock(spec=["_http"])
+        bucket = _Bucket(client)
+        blob = self._make_one(blob_name, bucket=bucket)
+
+        response = self._mock_requests_response(
+            http_client.OK,
+            headers={
+                "Content-Type": "application/json",
+                "Content-Language": "ko-kr",
+                "Cache-Control": "max-age=1337;public",
+                "Content-Encoding": "gzip",
+                "X-Goog-Storage-Class": "STANDARD",
+                "X-Goog-Hash": "crc32c=4gcgLQ==,md5=CS9tHYTtyFntzj7B9nkkJQ==",
+            },
+            # { "x": 5 } gzipped
+            content=b"\x1f\x8b\x08\x00\xcfo\x17_\x02\xff\xabVP\xaaP\xb2R0U\xa8\x05\x00\xa1\xcaQ\x93\n\x00\x00\x00",
+        )
+        blob._extract_headers_from_download(response)
+
+        self.assertEqual(blob.content_type, "application/json")
+        self.assertEqual(blob.content_language, "ko-kr")
+        self.assertEqual(blob.content_encoding, "gzip")
+        self.assertEqual(blob.cache_control, "max-age=1337;public")
+        self.assertEqual(blob.storage_class, "STANDARD")
+        self.assertEqual(blob.md5_hash, "CS9tHYTtyFntzj7B9nkkJQ==")
+        self.assertEqual(blob.crc32c, "4gcgLQ==")
+
+    def test__extract_headers_from_download_empty(self):
+        blob_name = "blob-name"
+        client = mock.Mock(spec=["_http"])
+        bucket = _Bucket(client)
+        blob = self._make_one(blob_name, bucket=bucket)
+
+        response = self._mock_requests_response(
+            http_client.OK,
+            headers={
+                "Content-Type": "application/octet-stream",
+                "Content-Language": "en-US",
+                "Cache-Control": "max-age=1337;public",
+                "Content-Encoding": "gzip",
+                "X-Goog-Storage-Class": "STANDARD",
+                "X-Goog-Hash": "crc32c=4/c+LQ==,md5=CS9tHYTt/+ntzj7B9nkkJQ==",
+            },
+            content=b"",
+        )
+        blob._extract_headers_from_download(response)
+        self.assertEqual(blob.content_type, "application/octet-stream")
+        self.assertEqual(blob.content_language, "en-US")
+        self.assertEqual(blob.md5_hash, "CS9tHYTt/+ntzj7B9nkkJQ==")
+        self.assertEqual(blob.crc32c, "4/c+LQ==")
+
+    def test__extract_headers_from_download_w_hash_response_header_none(self):
+        blob_name = "blob-name"
+        md5_hash = "CS9tHYTtyFntzj7B9nkkJQ=="
+        crc32c = "4gcgLQ=="
+        client = mock.Mock(spec=["_http"])
+        bucket = _Bucket(client)
+        properties = {
+            "md5Hash": md5_hash,
+            "crc32c": crc32c,
+        }
+        blob = self._make_one(blob_name, bucket=bucket, properties=properties)
+
+        response = self._mock_requests_response(
+            http_client.OK,
+            headers={"X-Goog-Hash": ""},
+            # { "x": 5 } gzipped
+            content=b"\x1f\x8b\x08\x00\xcfo\x17_\x02\xff\xabVP\xaaP\xb2R0U\xa8\x05\x00\xa1\xcaQ\x93\n\x00\x00\x00",
+        )
+        blob._extract_headers_from_download(response)
+
+        self.assertEqual(blob.md5_hash, md5_hash)
+        self.assertEqual(blob.crc32c, crc32c)
+
+    def test__extract_headers_from_download_w_response_headers_not_match(self):
+        blob_name = "blob-name"
+        client = mock.Mock(spec=["_http"])
+        bucket = _Bucket(client)
+        blob = self._make_one(blob_name, bucket=bucket)
+
+        response = self._mock_requests_response(
+            http_client.OK,
+            headers={"X-Goog-Hash": "bogus=4gcgLQ==,"},
+            # { "x": 5 } gzipped
+            content=b"",
+        )
+        blob._extract_headers_from_download(response)
+
+        self.assertIsNone(blob.md5_hash)
+        self.assertIsNone(blob.crc32c)
+
     def _do_download_helper_wo_chunks(self, w_range, raw_download, timeout=None):
         blob_name = "blob-name"
         client = mock.Mock()
@@ -1114,7 +1204,7 @@ class Test_Blob(unittest.TestCase):
         self, w_range, raw_download, timeout=None, checksum="md5"
     ):
         blob_name = "blob-name"
-        client = mock.Mock(_credentials=_make_credentials(), spec=["_credentials"])
+        client = self._make_client()
         bucket = _Bucket(client)
         blob = self._make_one(blob_name, bucket=bucket)
         blob._CHUNK_SIZE_MULTIPLE = 1
@@ -1217,41 +1307,32 @@ class Test_Blob(unittest.TestCase):
         patch.assert_not_called()
 
     def test_download_to_file_with_failure(self):
-        import requests
-        from google.resumable_media import InvalidResponse
-        from google.cloud import exceptions
-
-        raw_response = requests.Response()
-        raw_response.status_code = http_client.NOT_FOUND
-        raw_request = requests.Request("GET", "http://example.com")
-        raw_response.request = raw_request.prepare()
-        grmp_response = InvalidResponse(raw_response)
+        from google.cloud.exceptions import NotFound
 
         blob_name = "blob-name"
-        media_link = "http://test.invalid"
         client = self._make_client()
+        client.download_blob_to_file.side_effect = NotFound("testing")
         bucket = _Bucket(client)
         blob = self._make_one(blob_name, bucket=bucket)
-        blob._properties["mediaLink"] = media_link
-        blob._do_download = mock.Mock()
-        blob._do_download.side_effect = grmp_response
-
         file_obj = io.BytesIO()
-        with self.assertRaises(exceptions.NotFound):
+
+        with self.assertRaises(NotFound):
             blob.download_to_file(file_obj)
 
         self.assertEqual(file_obj.tell(), 0)
 
-        headers = {"accept-encoding": "gzip"}
-        blob._do_download.assert_called_once_with(
-            client._http,
+        expected_timeout = self._get_default_timeout()
+        client.download_blob_to_file.assert_called_once_with(
+            blob,
             file_obj,
-            media_link,
-            headers,
-            None,
-            None,
-            False,
-            timeout=self._get_default_timeout(),
+            start=None,
+            end=None,
+            if_generation_match=None,
+            if_generation_not_match=None,
+            if_metageneration_match=None,
+            if_metageneration_not_match=None,
+            raw_download=False,
+            timeout=expected_timeout,
             checksum="md5",
         )
 
@@ -1260,7 +1341,6 @@ class Test_Blob(unittest.TestCase):
         client = self._make_client()
         bucket = _Bucket(client)
         blob = self._make_one(blob_name, bucket=bucket)
-        blob._do_download = mock.Mock()
         file_obj = io.BytesIO()
 
         blob.download_to_file(file_obj)
@@ -1268,49 +1348,41 @@ class Test_Blob(unittest.TestCase):
         # Make sure the media link is still unknown.
         self.assertIsNone(blob.media_link)
 
-        expected_url = (
-            "https://storage.googleapis.com/download/storage/v1/b/"
-            "name/o/blob-name?alt=media"
-        )
-        headers = {"accept-encoding": "gzip"}
-        blob._do_download.assert_called_once_with(
-            client._http,
+        expected_timeout = self._get_default_timeout()
+        client.download_blob_to_file.assert_called_once_with(
+            blob,
             file_obj,
-            expected_url,
-            headers,
-            None,
-            None,
-            False,
-            timeout=self._get_default_timeout(),
+            start=None,
+            end=None,
+            if_generation_match=None,
+            if_generation_not_match=None,
+            if_metageneration_match=None,
+            if_metageneration_not_match=None,
+            raw_download=False,
+            timeout=expected_timeout,
             checksum="md5",
         )
 
     def test_download_to_file_w_generation_match(self):
-        GENERATION_NUMBER = 6
-        HEADERS = {"accept-encoding": "gzip"}
-        EXPECTED_URL = (
-            "https://storage.googleapis.com/download/storage/v1/b/"
-            "name/o/blob-name?alt=media&ifGenerationNotMatch={}".format(
-                GENERATION_NUMBER
-            )
-        )
-
+        generation_number = 6
         client = self._make_client()
         blob = self._make_one("blob-name", bucket=_Bucket(client))
-        blob._do_download = mock.Mock()
         file_obj = io.BytesIO()
 
-        blob.download_to_file(file_obj, if_generation_not_match=GENERATION_NUMBER)
+        blob.download_to_file(file_obj, if_generation_not_match=generation_number)
 
-        blob._do_download.assert_called_once_with(
-            client._http,
+        expected_timeout = self._get_default_timeout()
+        client.download_blob_to_file.assert_called_once_with(
+            blob,
             file_obj,
-            EXPECTED_URL,
-            HEADERS,
-            None,
-            None,
-            False,
-            timeout=self._get_default_timeout(),
+            start=None,
+            end=None,
+            if_generation_match=None,
+            if_generation_not_match=generation_number,
+            if_metageneration_match=None,
+            if_metageneration_not_match=None,
+            raw_download=False,
+            timeout=expected_timeout,
             checksum="md5",
         )
 
@@ -1324,7 +1396,6 @@ class Test_Blob(unittest.TestCase):
         if use_chunks:
             blob._CHUNK_SIZE_MULTIPLE = 1
             blob.chunk_size = 3
-        blob._do_download = mock.Mock()
 
         if timeout is None:
             expected_timeout = self._get_default_timeout()
@@ -1339,15 +1410,16 @@ class Test_Blob(unittest.TestCase):
         else:
             blob.download_to_file(file_obj, **timeout_kwarg)
 
-        headers = {"accept-encoding": "gzip"}
-        blob._do_download.assert_called_once_with(
-            client._http,
+        client.download_blob_to_file.assert_called_once_with(
+            blob,
             file_obj,
-            media_link,
-            headers,
-            None,
-            None,
-            raw_download,
+            start=None,
+            end=None,
+            if_generation_match=None,
+            if_generation_not_match=None,
+            if_metageneration_match=None,
+            if_metageneration_not_match=None,
+            raw_download=raw_download,
             timeout=expected_timeout,
             checksum="md5",
         )
@@ -1377,13 +1449,11 @@ class Test_Blob(unittest.TestCase):
         blob_name = "blob-name"
         client = self._make_client()
         bucket = _Bucket(client)
-        media_link = "http://example.com/media/"
-        properties = {"mediaLink": media_link}
+        properties = {}
         if updated is not None:
             properties["updated"] = updated
 
         blob = self._make_one(blob_name, bucket=bucket, properties=properties)
-        blob._do_download = mock.Mock()
 
         with _NamedTemporaryFile() as temp:
             if timeout is None:
@@ -1405,51 +1475,22 @@ class Test_Blob(unittest.TestCase):
 
         expected_timeout = self._get_default_timeout() if timeout is None else timeout
 
-        headers = {"accept-encoding": "gzip"}
-        blob._do_download.assert_called_once_with(
-            client._http,
+        client.download_blob_to_file.assert_called_once_with(
+            blob,
             mock.ANY,
-            media_link,
-            headers,
-            None,
-            None,
-            raw_download,
+            start=None,
+            end=None,
+            if_generation_match=None,
+            if_generation_not_match=None,
+            if_metageneration_match=None,
+            if_metageneration_not_match=None,
+            raw_download=raw_download,
             timeout=expected_timeout,
             checksum="md5",
         )
-        stream = blob._do_download.mock_calls[0].args[1]
+        stream = client.download_blob_to_file.mock_calls[0].args[1]
         self.assertEqual(stream.name, temp.name)
 
-    def test_download_to_filename_w_generation_match(self):
-        from google.cloud._testing import _NamedTemporaryFile
-
-        GENERATION_NUMBER = 6
-        MEDIA_LINK = "http://example.com/media/"
-        EXPECTED_LINK = MEDIA_LINK + "?ifGenerationMatch={}".format(GENERATION_NUMBER)
-        HEADERS = {"accept-encoding": "gzip"}
-
-        client = self._make_client()
-
-        blob = self._make_one(
-            "blob-name", bucket=_Bucket(client), properties={"mediaLink": MEDIA_LINK}
-        )
-        blob._do_download = mock.Mock()
-
-        with _NamedTemporaryFile() as temp:
-            blob.download_to_filename(temp.name, if_generation_match=GENERATION_NUMBER)
-
-        blob._do_download.assert_called_once_with(
-            client._http,
-            mock.ANY,
-            EXPECTED_LINK,
-            HEADERS,
-            None,
-            None,
-            False,
-            timeout=self._get_default_timeout(),
-            checksum="md5",
-        )
-
     def test_download_to_filename_w_updated_wo_raw(self):
         updated = "2014-12-06T13:13:50.690Z"
         self._download_to_filename_helper(updated=updated, raw_download=False)
@@ -1469,18 +1510,41 @@ class Test_Blob(unittest.TestCase):
             updated=None, raw_download=False, timeout=9.58
         )
 
+    def test_download_to_filename_w_generation_match(self):
+        from google.cloud._testing import _NamedTemporaryFile
+
+        generation_number = 6
+        client = self._make_client()
+        blob = self._make_one("blob-name", bucket=_Bucket(client))
+
+        with _NamedTemporaryFile() as temp:
+            blob.download_to_filename(temp.name, if_generation_match=generation_number)
+
+        expected_timeout = self._get_default_timeout()
+        client.download_blob_to_file.assert_called_once_with(
+            blob,
+            mock.ANY,
+            start=None,
+            end=None,
+            if_generation_match=generation_number,
+            if_generation_not_match=None,
+            if_metageneration_match=None,
+            if_metageneration_not_match=None,
+            raw_download=False,
+            timeout=expected_timeout,
+            checksum="md5",
+        )
+        stream = client.download_blob_to_file.mock_calls[0].args[1]
+        self.assertEqual(stream.name, temp.name)
+
     def test_download_to_filename_corrupted(self):
         from google.resumable_media import DataCorruption
 
         blob_name = "blob-name"
         client = self._make_client()
         bucket = _Bucket(client)
-        media_link = "http://example.com/media/"
-        properties = {"mediaLink": media_link}
-
-        blob = self._make_one(blob_name, bucket=bucket, properties=properties)
-        blob._do_download = mock.Mock()
-        blob._do_download.side_effect = DataCorruption("testing")
+        blob = self._make_one(blob_name, bucket=bucket)
+        client.download_blob_to_file.side_effect = DataCorruption("testing")
 
         # Try to download into a temporary file (don't use
         # `_NamedTemporaryFile` it will try to remove after the file is
@@ -1495,64 +1559,28 @@ class Test_Blob(unittest.TestCase):
         # Make sure the file was cleaned up.
         self.assertFalse(os.path.exists(filename))
 
-        headers = {"accept-encoding": "gzip"}
-        blob._do_download.assert_called_once_with(
-            client._http,
+        expected_timeout = self._get_default_timeout()
+        client.download_blob_to_file.assert_called_once_with(
+            blob,
             mock.ANY,
-            media_link,
-            headers,
-            None,
-            None,
-            False,
-            timeout=self._get_default_timeout(),
+            start=None,
+            end=None,
+            if_generation_match=None,
+            if_generation_not_match=None,
+            if_metageneration_match=None,
+            if_metageneration_not_match=None,
+            raw_download=False,
+            timeout=expected_timeout,
             checksum="md5",
         )
-        stream = blob._do_download.mock_calls[0].args[1]
+        stream = client.download_blob_to_file.mock_calls[0].args[1]
         self.assertEqual(stream.name, filename)
 
-    def test_download_to_filename_w_key(self):
-        from google.cloud._testing import _NamedTemporaryFile
-        from google.cloud.storage.blob import _get_encryption_headers
-
-        blob_name = "blob-name"
-        # Create a fake client/bucket and use them in the Blob() constructor.
-        client = self._make_client()
-        bucket = _Bucket(client)
-        media_link = "http://example.com/media/"
-        properties = {"mediaLink": media_link}
-        key = b"aa426195405adee2c8081bb9e7e74b19"
-        blob = self._make_one(
-            blob_name, bucket=bucket, properties=properties, encryption_key=key
-        )
-        blob._do_download = mock.Mock()
-
-        with _NamedTemporaryFile() as temp:
-            blob.download_to_filename(temp.name)
-
-        headers = {"accept-encoding": "gzip"}
-        headers.update(_get_encryption_headers(key))
-        blob._do_download.assert_called_once_with(
-            client._http,
-            mock.ANY,
-            media_link,
-            headers,
-            None,
-            None,
-            False,
-            timeout=self._get_default_timeout(),
-            checksum="md5",
-        )
-        stream = blob._do_download.mock_calls[0].args[1]
-        self.assertEqual(stream.name, temp.name)
-
     def _download_as_bytes_helper(self, raw_download, timeout=None):
         blob_name = "blob-name"
         client = self._make_client()
         bucket = _Bucket(client)
-        media_link = "http://example.com/media/"
-        properties = {"mediaLink": media_link}
-        blob = self._make_one(blob_name, bucket=bucket, properties=properties)
-        blob._do_download = mock.Mock()
+        blob = self._make_one(blob_name, bucket=bucket)
 
         if timeout is None:
             expected_timeout = self._get_default_timeout()
@@ -1562,113 +1590,30 @@ class Test_Blob(unittest.TestCase):
             fetched = blob.download_as_bytes(raw_download=raw_download, timeout=timeout)
         self.assertEqual(fetched, b"")
 
-        headers = {"accept-encoding": "gzip"}
-        blob._do_download.assert_called_once_with(
-            client._http,
+        client.download_blob_to_file.assert_called_once_with(
+            blob,
             mock.ANY,
-            media_link,
-            headers,
-            None,
-            None,
-            raw_download,
+            start=None,
+            end=None,
+            if_generation_match=None,
+            if_generation_not_match=None,
+            if_metageneration_match=None,
+            if_metageneration_not_match=None,
+            raw_download=raw_download,
             timeout=expected_timeout,
             checksum="md5",
         )
-        stream = blob._do_download.mock_calls[0].args[1]
+        stream = client.download_blob_to_file.mock_calls[0].args[1]
         self.assertIsInstance(stream, io.BytesIO)
 
-    def test_download_as_string_w_response_headers(self):
-        blob_name = "blob-name"
-        client = mock.Mock(spec=["_http"])
-        bucket = _Bucket(client)
-        media_link = "http://example.com/media/"
-        properties = {"mediaLink": media_link}
-        blob = self._make_one(blob_name, bucket=bucket, properties=properties)
-
-        response = self._mock_requests_response(
-            http_client.OK,
-            headers={
-                "Content-Type": "application/json",
-                "Content-Language": "ko-kr",
-                "Cache-Control": "max-age=1337;public",
-                "Content-Encoding": "gzip",
-                "X-Goog-Storage-Class": "STANDARD",
-                "X-Goog-Hash": "crc32c=4gcgLQ==,md5=CS9tHYTtyFntzj7B9nkkJQ==",
-            },
-            # { "x": 5 } gzipped
-            content=b"\x1f\x8b\x08\x00\xcfo\x17_\x02\xff\xabVP\xaaP\xb2R0U\xa8\x05\x00\xa1\xcaQ\x93\n\x00\x00\x00",
-        )
-        blob._extract_headers_from_download(response)
-
-        self.assertEqual(blob.content_type, "application/json")
-        self.assertEqual(blob.content_language, "ko-kr")
-        self.assertEqual(blob.content_encoding, "gzip")
-        self.assertEqual(blob.cache_control, "max-age=1337;public")
-        self.assertEqual(blob.storage_class, "STANDARD")
-        self.assertEqual(blob.md5_hash, "CS9tHYTtyFntzj7B9nkkJQ==")
-        self.assertEqual(blob.crc32c, "4gcgLQ==")
-
-        response = self._mock_requests_response(
-            http_client.OK,
-            headers={
-                "Content-Type": "application/octet-stream",
-                "Content-Language": "en-US",
-                "Cache-Control": "max-age=1337;public",
-                "Content-Encoding": "gzip",
-                "X-Goog-Storage-Class": "STANDARD",
-                "X-Goog-Hash": "crc32c=4/c+LQ==,md5=CS9tHYTt/+ntzj7B9nkkJQ==",
-            },
-            content=b"",
-        )
-        blob._extract_headers_from_download(response)
-        self.assertEqual(blob.content_type, "application/octet-stream")
-        self.assertEqual(blob.content_language, "en-US")
-        self.assertEqual(blob.md5_hash, "CS9tHYTt/+ntzj7B9nkkJQ==")
-        self.assertEqual(blob.crc32c, "4/c+LQ==")
-
-    def test_download_as_string_w_hash_response_header_none(self):
-        blob_name = "blob-name"
-        md5_hash = "CS9tHYTtyFntzj7B9nkkJQ=="
-        crc32c = "4gcgLQ=="
-        client = mock.Mock(spec=["_http"])
-        bucket = _Bucket(client)
-        media_link = "http://example.com/media/"
-        properties = {
-            "mediaLink": media_link,
-            "md5Hash": md5_hash,
-            "crc32c": crc32c,
-        }
-        blob = self._make_one(blob_name, bucket=bucket, properties=properties)
-
-        response = self._mock_requests_response(
-            http_client.OK,
-            headers={"X-Goog-Hash": ""},
-            # { "x": 5 } gzipped
-            content=b"\x1f\x8b\x08\x00\xcfo\x17_\x02\xff\xabVP\xaaP\xb2R0U\xa8\x05\x00\xa1\xcaQ\x93\n\x00\x00\x00",
-        )
-        blob._extract_headers_from_download(response)
-
-        self.assertEqual(blob.md5_hash, md5_hash)
-        self.assertEqual(blob.crc32c, crc32c)
-
-    def test_download_as_string_w_response_headers_not_match(self):
-        blob_name = "blob-name"
-        client = mock.Mock(spec=["_http"])
-        bucket = _Bucket(client)
-        media_link = "http://example.com/media/"
-        properties = {"mediaLink": media_link}
-        blob = self._make_one(blob_name, bucket=bucket, properties=properties)
+    def test_download_as_bytes_wo_raw(self):
+        self._download_as_bytes_helper(raw_download=False)
 
-        response = self._mock_requests_response(
-            http_client.OK,
-            headers={"X-Goog-Hash": "bogus=4gcgLQ==,"},
-            # { "x": 5 } gzipped
-            content=b"",
-        )
-        blob._extract_headers_from_download(response)
+    def test_download_as_bytes_w_raw(self):
+        self._download_as_bytes_helper(raw_download=True)
 
-        self.assertIsNone(blob.md5_hash)
-        self.assertIsNone(blob.crc32c)
+    def test_download_as_bytes_w_custom_timeout(self):
+        self._download_as_bytes_helper(raw_download=False, timeout=9.58)
 
     def test_download_as_bytes_w_generation_match(self):
         GENERATION_NUMBER = 6
@@ -1697,15 +1642,6 @@ class Test_Blob(unittest.TestCase):
             checksum="md5",
         )
 
-    def test_download_as_bytes_wo_raw(self):
-        self._download_as_bytes_helper(raw_download=False)
-
-    def test_download_as_bytes_w_raw(self):
-        self._download_as_bytes_helper(raw_download=True)
-
-    def test_download_as_byte_w_custom_timeout(self):
-        self._download_as_bytes_helper(raw_download=False, timeout=9.58)
-
     def _download_as_text_helper(
         self,
         raw_download,
@@ -1730,7 +1666,8 @@ class Test_Blob(unittest.TestCase):
                 payload = expected_value.encode()
 
         blob_name = "blob-name"
-        bucket = _Bucket()
+        bucket_client = self._make_client()
+        bucket = _Bucket(bucket_client)
 
         properties = {}
         if charset is not None:
@@ -4804,8 +4741,7 @@ class Test_Blob(unittest.TestCase):
     def test_from_string_w_valid_uri(self):
         from google.cloud.storage.blob import Blob
 
-        connection = _Connection()
-        client = _Client(connection)
+        client = self._make_client()
         uri = "gs://BUCKET_NAME/b"
         blob = Blob.from_string(uri, client)
 
@@ -4817,8 +4753,7 @@ class Test_Blob(unittest.TestCase):
     def test_from_string_w_invalid_uri(self):
         from google.cloud.storage.blob import Blob
 
-        connection = _Connection()
-        client = _Client(connection)
+        client = self._make_client()
 
         with pytest.raises(ValueError, match="URI scheme must be gs"):
             Blob.from_string("http://bucket_name/b", client)
@@ -4826,8 +4761,7 @@ class Test_Blob(unittest.TestCase):
     def test_from_string_w_domain_name_bucket(self):
         from google.cloud.storage.blob import Blob
 
-        connection = _Connection()
-        client = _Client(connection)
+        client = self._make_client()
         uri = "gs://buckets.example.com/b"
         blob = Blob.from_string(uri, client)
 
@@ -5015,15 +4949,12 @@ class _Connection(object):
     USER_AGENT = "testing 1.2.3"
     credentials = object()
 
-    def __init__(self):
-        pass
-
 
 class _Bucket(object):
     def __init__(self, client=None, name="name", user_project=None):
         if client is None:
-            connection = _Connection()
-            client = _Client(connection)
+            client = Test_Blob._make_client()
+
         self.client = client
         self._blobs = {}
         self._copied = []
@@ -5058,12 +4989,3 @@ class _Bucket(object):
                 retry,
             )
         )
-
-
-class _Client(object):
-    def __init__(self, connection):
-        self._base_connection = connection
-
-    @property
-    def _credentials(self):
-        return self._base_connection.credentials
diff --git a/tests/unit/test_bucket.py b/tests/unit/test_bucket.py
index 63c1e4d..244c26b 100644
--- a/tests/unit/test_bucket.py
+++ b/tests/unit/test_bucket.py
@@ -37,6 +37,79 @@ def _create_signing_credentials():
     return credentials
 
 
+class Test__blobs_page_start(unittest.TestCase):
+    @staticmethod
+    def _call_fut(iterator, page, response):
+        from google.cloud.storage.bucket import _blobs_page_start
+
+        return _blobs_page_start(iterator, page, response)
+
+    def test_wo_any_prefixes(self):
+        iterator = mock.Mock(spec=["prefixes"], prefixes=set())
+        page = mock.Mock(spec=["prefixes"])
+        response = {}
+
+        self._call_fut(iterator, page, response)
+
+        self.assertEqual(page.prefixes, ())
+        self.assertEqual(iterator.prefixes, set())
+
+    def test_w_prefixes(self):
+        iterator_prefixes = set(["foo/", "qux/"])
+        iterator = mock.Mock(spec=["prefixes"], prefixes=iterator_prefixes)
+        page = mock.Mock(spec=["prefixes"])
+        page_prefixes = ["foo/", "bar/", "baz/"]
+        response = {"prefixes": page_prefixes}
+
+        self._call_fut(iterator, page, response)
+
+        self.assertEqual(page.prefixes, tuple(page_prefixes))
+        self.assertEqual(iterator.prefixes, iterator_prefixes.union(page_prefixes))
+
+
+class Test__item_to_blob(unittest.TestCase):
+    @staticmethod
+    def _call_fut(iterator, item):
+        from google.cloud.storage.bucket import _item_to_blob
+
+        return _item_to_blob(iterator, item)
+
+    def test_wo_extra_properties(self):
+        from google.cloud.storage.blob import Blob
+
+        blob_name = "blob-name"
+        bucket = mock.Mock(spec=[])
+        iterator = mock.Mock(spec=["bucket"], bucket=bucket)
+        item = {"name": blob_name}
+
+        blob = self._call_fut(iterator, item)
+
+        self.assertIsInstance(blob, Blob)
+        self.assertIs(blob.bucket, bucket)
+        self.assertEqual(blob.name, blob_name)
+        self.assertEqual(blob._properties, item)
+
+    def test_w_extra_properties(self):
+        from google.cloud.storage.blob import Blob
+
+        blob_name = "blob-name"
+        bucket = mock.Mock(spec=[])
+        iterator = mock.Mock(spec=["bucket"], bucket=bucket)
+        item = {
+            "name": blob_name,
+            "generation": 123,
+            "contentType": "text/plain",
+            "contentLanguage": "en-US",
+        }
+
+        blob = self._call_fut(iterator, item)
+
+        self.assertIsInstance(blob, Blob)
+        self.assertIs(blob.bucket, bucket)
+        self.assertEqual(blob.name, blob_name)
+        self.assertEqual(blob._properties, item)
+
+
 class Test_LifecycleRuleConditions(unittest.TestCase):
     @staticmethod
     def _get_target_class():
@@ -442,15 +515,14 @@ class Test_Bucket(unittest.TestCase):
         return _DEFAULT_TIMEOUT
 
     @staticmethod
-    def _make_client(*args, **kw):
+    def _make_client(**kw):
         from google.cloud.storage.client import Client
 
-        return Client(*args, **kw)
+        return mock.create_autospec(Client, instance=True, **kw)
 
     def _make_one(self, client=None, name=None, properties=None, user_project=None):
         if client is None:
-            connection = _Connection()
-            client = _Client(connection)
+            client = self._make_client()
         if user_project is None:
             bucket = self._get_target_class()(client, name=name)
         else:
@@ -482,8 +554,7 @@ class Test_Bucket(unittest.TestCase):
     def test_ctor_w_user_project(self):
         NAME = "name"
         USER_PROJECT = "user-project-123"
-        connection = _Connection()
-        client = _Client(connection)
+        client = self._make_client()
         bucket = self._make_one(client, name=NAME, user_project=USER_PROJECT)
         self.assertEqual(bucket.name, NAME)
         self.assertEqual(bucket._properties, {})
@@ -575,7 +646,7 @@ class Test_Bucket(unittest.TestCase):
         PROJECT = "PROJECT"
         BUCKET_NAME = "BUCKET_NAME"
         TOPIC_NAME = "TOPIC_NAME"
-        client = _Client(_Connection(), project=PROJECT)
+        client = self._make_client(project=PROJECT)
         bucket = self._make_one(client, name=BUCKET_NAME)
 
         notification = bucket.notification(TOPIC_NAME)
@@ -603,7 +674,7 @@ class Test_Bucket(unittest.TestCase):
         CUSTOM_ATTRIBUTES = {"attr1": "value1", "attr2": "value2"}
         EVENT_TYPES = [OBJECT_FINALIZE_EVENT_TYPE, OBJECT_DELETE_EVENT_TYPE]
         BLOB_NAME_PREFIX = "blob-name-prefix/"
-        client = _Client(_Connection(), project=PROJECT)
+        client = self._make_client(project=PROJECT)
         bucket = self._make_one(client, name=BUCKET_NAME)
 
         notification = bucket.notification(
@@ -1609,8 +1680,7 @@ class Test_Bucket(unittest.TestCase):
         )
 
     def test_reload_w_generation_match(self):
-        connection = _Connection()
-        client = _Client(connection)
+        client = self._make_client()
         bucket = self._make_one(client=client, name="name")
 
         with self.assertRaises(TypeError):
@@ -3351,96 +3421,14 @@ class Test_Bucket(unittest.TestCase):
 
         client.list_blobs.assert_called_once()
 
-    def test_page_empty_response(self):
-        from google.api_core import page_iterator
-
-        connection = _Connection()
-        client = self._make_client()
-        client._base_connection = connection
-        name = "name"
-        bucket = self._make_one(client=client, name=name)
-        iterator = bucket.list_blobs()
-        page = page_iterator.Page(iterator, (), None)
-        iterator._page = page
-        blobs = list(page)
-        self.assertEqual(blobs, [])
-        self.assertEqual(iterator.prefixes, set())
-
-    def test_page_non_empty_response(self):
-        import six
-        from google.cloud.storage.blob import Blob
-
-        blob_name = "blob-name"
-        response = {"items": [{"name": blob_name}], "prefixes": ["foo"]}
-        connection = _Connection()
-        client = self._make_client()
-        client._base_connection = connection
-        name = "name"
-        bucket = self._make_one(client=client, name=name)
-
-        def fake_response():
-            return response
-
-        iterator = bucket.list_blobs()
-        iterator._get_next_page_response = fake_response
-
-        page = six.next(iterator.pages)
-        self.assertEqual(page.prefixes, ("foo",))
-        self.assertEqual(page.num_items, 1)
-        blob = six.next(page)
-        self.assertEqual(page.remaining, 0)
-        self.assertIsInstance(blob, Blob)
-        self.assertEqual(blob.name, blob_name)
-        self.assertEqual(iterator.prefixes, set(["foo"]))
-
-    def test_cumulative_prefixes(self):
-        import six
-        from google.cloud.storage.blob import Blob
-
-        BLOB_NAME = "blob-name1"
-        response1 = {
-            "items": [{"name": BLOB_NAME}],
-            "prefixes": ["foo"],
-            "nextPageToken": "s39rmf9",
-        }
-        response2 = {"items": [], "prefixes": ["bar"]}
-        client = self._make_client()
-        name = "name"
-        bucket = self._make_one(client=client, name=name)
-        responses = [response1, response2]
-
-        def fake_response():
-            return responses.pop(0)
-
-        iterator = bucket.list_blobs()
-        iterator._get_next_page_response = fake_response
-
-        # Parse first response.
-        pages_iter = iterator.pages
-        page1 = six.next(pages_iter)
-        self.assertEqual(page1.prefixes, ("foo",))
-        self.assertEqual(page1.num_items, 1)
-        blob = six.next(page1)
-        self.assertEqual(page1.remaining, 0)
-        self.assertIsInstance(blob, Blob)
-        self.assertEqual(blob.name, BLOB_NAME)
-        self.assertEqual(iterator.prefixes, set(["foo"]))
-        # Parse second response.
-        page2 = six.next(pages_iter)
-        self.assertEqual(page2.prefixes, ("bar",))
-        self.assertEqual(page2.num_items, 0)
-        self.assertEqual(iterator.prefixes, set(["foo", "bar"]))
-
-    def _test_generate_upload_policy_helper(self, **kwargs):
+    def _generate_upload_policy_helper(self, **kwargs):
         import base64
         import json
 
         credentials = _create_signing_credentials()
         credentials.signer_email = mock.sentinel.signer_email
         credentials.sign_bytes.return_value = b"DEADBEEF"
-        connection = _Connection()
-        connection.credentials = credentials
-        client = _Client(connection)
+        client = self._make_client(_credentials=credentials)
         name = "name"
         bucket = self._make_one(client=client, name=name)
 
@@ -3477,7 +3465,7 @@ class Test_Bucket(unittest.TestCase):
     def test_generate_upload_policy(self, now):
         from google.cloud._helpers import _datetime_to_rfc3339
 
-        _, policy = self._test_generate_upload_policy_helper()
+        _, policy = self._generate_upload_policy_helper()
 
         self.assertEqual(
             policy["expiration"],
@@ -3489,15 +3477,13 @@ class Test_Bucket(unittest.TestCase):
 
         expiration = datetime.datetime(1990, 5, 29)
 
-        _, policy = self._test_generate_upload_policy_helper(expiration=expiration)
+        _, policy = self._generate_upload_policy_helper(expiration=expiration)
 
         self.assertEqual(policy["expiration"], _datetime_to_rfc3339(expiration))
 
     def test_generate_upload_policy_bad_credentials(self):
         credentials = object()
-        connection = _Connection()
-        connection.credentials = credentials
-        client = _Client(connection)
+        client = self._make_client(_credentials=credentials)
         name = "name"
         bucket = self._make_one(client=client, name=name)
 
@@ -3628,8 +3614,7 @@ class Test_Bucket(unittest.TestCase):
 
     def test_generate_signed_url_w_invalid_version(self):
         expiration = "2014-10-16T20:34:37.000Z"
-        connection = _Connection()
-        client = _Client(connection)
+        client = self._make_client()
         bucket = self._make_one(name="bucket_name", client=client)
         with self.assertRaises(ValueError):
             bucket.generate_signed_url(expiration, version="nonesuch")
@@ -3665,8 +3650,7 @@ class Test_Bucket(unittest.TestCase):
         if expiration is None:
             expiration = datetime.datetime.utcnow().replace(tzinfo=UTC) + delta
 
-        connection = _Connection()
-        client = _Client(connection)
+        client = self._make_client(_credentials=credentials)
         bucket = self._make_one(name=bucket_name, client=client)
 
         if version is None:
@@ -3726,11 +3710,12 @@ class Test_Bucket(unittest.TestCase):
     def test_get_bucket_from_string_w_valid_uri(self):
         from google.cloud.storage.bucket import Bucket
 
-        connection = _Connection()
-        client = _Client(connection)
+        client = self._make_client()
         BUCKET_NAME = "BUCKET_NAME"
         uri = "gs://" + BUCKET_NAME
+
         bucket = Bucket.from_string(uri, client)
+
         self.assertIsInstance(bucket, Bucket)
         self.assertIs(bucket.client, client)
         self.assertEqual(bucket.name, BUCKET_NAME)
@@ -3738,8 +3723,7 @@ class Test_Bucket(unittest.TestCase):
     def test_get_bucket_from_string_w_invalid_uri(self):
         from google.cloud.storage.bucket import Bucket
 
-        connection = _Connection()
-        client = _Client(connection)
+        client = self._make_client()
 
         with pytest.raises(ValueError, match="URI scheme must be gs"):
             Bucket.from_string("http://bucket_name", client)
@@ -3747,11 +3731,12 @@ class Test_Bucket(unittest.TestCase):
     def test_get_bucket_from_string_w_domain_name_bucket(self):
         from google.cloud.storage.bucket import Bucket
 
-        connection = _Connection()
-        client = _Client(connection)
+        client = self._make_client()
         BUCKET_NAME = "buckets.example.com"
         uri = "gs://" + BUCKET_NAME
+
         bucket = Bucket.from_string(uri, client)
+
         self.assertIsInstance(bucket, Bucket)
         self.assertIs(bucket.client, client)
         self.assertEqual(bucket.name, BUCKET_NAME)
@@ -3886,23 +3871,3 @@ class Test__item_to_notification(unittest.TestCase):
         self.assertEqual(notification._topic_name, topic)
         self.assertEqual(notification._topic_project, project)
         self.assertEqual(notification._properties, item)
-
-
-class _Connection(object):
-    credentials = None
-
-    def __init__(self):
-        pass
-
-    def api_request(self, **kw):  # pragma: NO COVER
-        pass
-
-
-class _Client(object):
-    def __init__(self, connection, project=None):
-        self._base_connection = connection
-        self.project = project
-
-    @property
-    def _credentials(self):
-        return self._base_connection.credentials
diff --git a/tests/unit/test_client.py b/tests/unit/test_client.py
index 50ce3c1..4c99a38 100644
--- a/tests/unit/test_client.py
+++ b/tests/unit/test_client.py
@@ -219,7 +219,8 @@ class TestClient(unittest.TestCase):
         self.assertIs(client._connection._client_info, client_info)
 
     def test_ctor_mtls(self):
-        credentials = _make_credentials()
+        PROJECT = "PROJECT"
+        credentials = _make_credentials(project=PROJECT)
 
         client = self._make_one(credentials=credentials)
         self.assertEqual(client._connection.ALLOW_AUTO_SWITCH_TO_MTLS_URL, True)
@@ -1370,13 +1371,13 @@ class TestClient(unittest.TestCase):
         from google.cloud.storage.blob import Blob
         from google.cloud.storage.constants import _DEFAULT_TIMEOUT
 
+        project = "PROJECT"
         raw_response = requests.Response()
         raw_response.status_code = http_client.NOT_FOUND
         raw_request = requests.Request("GET", "http://example.com")
         raw_response.request = raw_request.prepare()
         grmp_response = InvalidResponse(raw_response)
-
-        credentials = _make_credentials()
+        credentials = _make_credentials(project=project)
         client = self._make_one(credentials=credentials)
         blob = mock.create_autospec(Blob)
         blob._encryption_key = None
@@ -1407,7 +1408,7 @@ class TestClient(unittest.TestCase):
         from google.cloud.storage.constants import _DEFAULT_TIMEOUT
 
         project = "PROJECT"
-        credentials = _make_credentials()
+        credentials = _make_credentials(project=project)
         client = self._make_one(project=project, credentials=credentials)
         blob = mock.Mock()
         file_obj = io.BytesIO()
@@ -1435,7 +1436,7 @@ class TestClient(unittest.TestCase):
 
     def test_download_blob_to_file_with_invalid_uri(self):
         project = "PROJECT"
-        credentials = _make_credentials()
+        credentials = _make_credentials(project=project)
         client = self._make_one(project=project, credentials=credentials)
         file_obj = io.BytesIO()
 
@@ -1446,7 +1447,8 @@ class TestClient(unittest.TestCase):
         from google.cloud.storage.blob import Blob
         from google.cloud.storage.constants import _DEFAULT_TIMEOUT
 
-        credentials = _make_credentials()
+        project = "PROJECT"
+        credentials = _make_credentials(project=project)
         client = self._make_one(credentials=credentials)
         blob = mock.create_autospec(Blob)
         blob._encryption_key = None
@@ -1955,7 +1957,9 @@ class TestClient(unittest.TestCase):
         EXPECTED_SIGN = "5369676e61747572655f6279746573"
         EXPECTED_POLICY = "eyJjb25kaXRpb25zIjpbeyJidWNrZXQiOiJidWNrZXQtbmFtZSJ9LHsiYWNsIjoicHJpdmF0ZSJ9LFsic3RhcnRzLXdpdGgiLCIkQ29udGVudC1UeXBlIiwidGV4dC9wbGFpbiJdLHsiYnVja2V0IjoiYnVja2V0LW5hbWUifSx7ImtleSI6Im9iamVjdC1uYW1lIn0seyJ4LWdvb2ctZGF0ZSI6IjIwMjAwMzEyVDExNDcxNloifSx7IngtZ29vZy1jcmVkZW50aWFsIjoidGVzdEBtYWlsLmNvbS8yMDIwMDMxMi9hdXRvL3N0b3JhZ2UvZ29vZzRfcmVxdWVzdCJ9LHsieC1nb29nLWFsZ29yaXRobSI6IkdPT0c0LVJTQS1TSEEyNTYifV0sImV4cGlyYXRpb24iOiIyMDIwLTAzLTI2VDAwOjAwOjEwWiJ9"
 
-        client = self._make_one(project="PROJECT")
+        project = "PROJECT"
+        credentials = _make_credentials(project=project)
+        client = self._make_one(credentials=credentials)
 
         dtstamps_patch, now_patch, expire_secs_patch = _time_functions_patches()
         with dtstamps_patch, now_patch, expire_secs_patch:
@@ -2033,7 +2037,9 @@ class TestClient(unittest.TestCase):
         EXPECTED_SIGN = "5369676e61747572655f6279746573"
         EXPECTED_POLICY = "eyJjb25kaXRpb25zIjpbeyJidWNrZXQiOiJidWNrZXQtbmFtZSJ9LHsiYWNsIjoicHJpdmF0ZSJ9LFsic3RhcnRzLXdpdGgiLCIkQ29udGVudC1UeXBlIiwidGV4dC9wbGFpbiJdLHsiZmllbGQxIjoiVmFsdWUxIn0seyJidWNrZXQiOiJidWNrZXQtbmFtZSJ9LHsia2V5Ijoib2JqZWN0LW5hbWUifSx7IngtZ29vZy1kYXRlIjoiMjAyMDAzMTJUMTE0NzE2WiJ9LHsieC1nb29nLWNyZWRlbnRpYWwiOiJ0ZXN0QG1haWwuY29tLzIwMjAwMzEyL2F1dG8vc3RvcmFnZS9nb29nNF9yZXF1ZXN0In0seyJ4LWdvb2ctYWxnb3JpdGhtIjoiR09PRzQtUlNBLVNIQTI1NiJ9XSwiZXhwaXJhdGlvbiI6IjIwMjAtMDMtMjZUMDA6MDA6MTBaIn0="
 
-        client = self._make_one(project="PROJECT")
+        project = "PROJECT"
+        credentials = _make_credentials(project=project)
+        client = self._make_one(credentials=credentials)
 
         dtstamps_patch, now_patch, expire_secs_patch = _time_functions_patches()
         with dtstamps_patch, now_patch, expire_secs_patch:
@@ -2071,7 +2077,9 @@ class TestClient(unittest.TestCase):
 
         BUCKET_NAME = "bucket-name"
 
-        client = self._make_one(project="PROJECT")
+        project = "PROJECT"
+        credentials = _make_credentials(project=project)
+        client = self._make_one(credentials=credentials)
 
         dtstamps_patch, _, _ = _time_functions_patches()
         with dtstamps_patch:
@@ -2089,7 +2097,9 @@ class TestClient(unittest.TestCase):
     def test_get_signed_policy_v4_bucket_bound_hostname(self):
         import datetime
 
-        client = self._make_one(project="PROJECT")
+        project = "PROJECT"
+        credentials = _make_credentials(project=project)
+        client = self._make_one(credentials=credentials)
 
         dtstamps_patch, _, _ = _time_functions_patches()
         with dtstamps_patch:
@@ -2105,7 +2115,9 @@ class TestClient(unittest.TestCase):
     def test_get_signed_policy_v4_bucket_bound_hostname_with_scheme(self):
         import datetime
 
-        client = self._make_one(project="PROJECT")
+        project = "PROJECT"
+        credentials = _make_credentials(project=project)
+        client = self._make_one(credentials=credentials)
 
         dtstamps_patch, _, _ = _time_functions_patches()
         with dtstamps_patch:
@@ -2123,7 +2135,9 @@ class TestClient(unittest.TestCase):
         BUCKET_NAME = "bucket-name"
         EXPECTED_POLICY = "eyJjb25kaXRpb25zIjpbeyJidWNrZXQiOiJidWNrZXQtbmFtZSJ9LHsia2V5Ijoib2JqZWN0LW5hbWUifSx7IngtZ29vZy1kYXRlIjoiMjAyMDAzMTJUMTE0NzE2WiJ9LHsieC1nb29nLWNyZWRlbnRpYWwiOiJ0ZXN0QG1haWwuY29tLzIwMjAwMzEyL2F1dG8vc3RvcmFnZS9nb29nNF9yZXF1ZXN0In0seyJ4LWdvb2ctYWxnb3JpdGhtIjoiR09PRzQtUlNBLVNIQTI1NiJ9XSwiZXhwaXJhdGlvbiI6IjIwMjAtMDMtMjZUMDA6MDA6MTBaIn0="
 
-        client = self._make_one(project="PROJECT")
+        project = "PROJECT"
+        credentials = _make_credentials(project=project)
+        client = self._make_one(credentials=credentials)
 
         dtstamps_patch, now_patch, expire_secs_patch = _time_functions_patches()
         with dtstamps_patch, now_patch, expire_secs_patch:
@@ -2147,7 +2161,9 @@ class TestClient(unittest.TestCase):
         EXPECTED_SIGN = "0c4003044105"
         EXPECTED_POLICY = "eyJjb25kaXRpb25zIjpbeyJidWNrZXQiOiJidWNrZXQtbmFtZSJ9LHsiYWNsIjoicHJpdmF0ZSJ9LFsic3RhcnRzLXdpdGgiLCIkQ29udGVudC1UeXBlIiwidGV4dC9wbGFpbiJdLHsiYnVja2V0IjoiYnVja2V0LW5hbWUifSx7ImtleSI6Im9iamVjdC1uYW1lIn0seyJ4LWdvb2ctZGF0ZSI6IjIwMjAwMzEyVDExNDcxNloifSx7IngtZ29vZy1jcmVkZW50aWFsIjoidGVzdEBtYWlsLmNvbS8yMDIwMDMxMi9hdXRvL3N0b3JhZ2UvZ29vZzRfcmVxdWVzdCJ9LHsieC1nb29nLWFsZ29yaXRobSI6IkdPT0c0LVJTQS1TSEEyNTYifV0sImV4cGlyYXRpb24iOiIyMDIwLTAzLTI2VDAwOjAwOjEwWiJ9"
 
-        client = self._make_one(project="PROJECT")
+        project = "PROJECT"
+        credentials = _make_credentials(project=project)
+        client = self._make_one(credentials=credentials)
 
         dtstamps_patch, now_patch, expire_secs_patch = _time_functions_patches()
         with dtstamps_patch, now_patch, expire_secs_patch: