Vehicle-Anti-Theft-Face-Rec.../venv/Lib/site-packages/gcloud/storage/test_blob.py

1398 lines
54 KiB
Python

# Copyright 2014 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import unittest2
class Test_Blob(unittest2.TestCase):
def _makeOne(self, *args, **kw):
from gcloud.storage.blob import Blob
properties = kw.pop('properties', None)
blob = Blob(*args, **kw)
blob._properties = properties or {}
return blob
def test_ctor(self):
BLOB_NAME = 'blob-name'
bucket = _Bucket()
properties = {'key': 'value'}
blob = self._makeOne(BLOB_NAME, bucket=bucket, properties=properties)
self.assertTrue(blob.bucket is bucket)
self.assertEqual(blob.name, BLOB_NAME)
self.assertEqual(blob._properties, properties)
self.assertFalse(blob._acl.loaded)
self.assertTrue(blob._acl.blob is blob)
def test_chunk_size_ctor(self):
from gcloud.storage.blob import Blob
BLOB_NAME = 'blob-name'
BUCKET = object()
chunk_size = 10 * Blob._CHUNK_SIZE_MULTIPLE
blob = self._makeOne(BLOB_NAME, bucket=BUCKET, chunk_size=chunk_size)
self.assertEqual(blob._chunk_size, chunk_size)
def test_chunk_size_getter(self):
BLOB_NAME = 'blob-name'
BUCKET = object()
blob = self._makeOne(BLOB_NAME, bucket=BUCKET)
self.assertEqual(blob.chunk_size, None)
VALUE = object()
blob._chunk_size = VALUE
self.assertTrue(blob.chunk_size is VALUE)
def test_chunk_size_setter(self):
BLOB_NAME = 'blob-name'
BUCKET = object()
blob = self._makeOne(BLOB_NAME, bucket=BUCKET)
self.assertEqual(blob._chunk_size, None)
blob._CHUNK_SIZE_MULTIPLE = 10
blob.chunk_size = 20
self.assertEqual(blob._chunk_size, 20)
def test_chunk_size_setter_bad_value(self):
BLOB_NAME = 'blob-name'
BUCKET = object()
blob = self._makeOne(BLOB_NAME, bucket=BUCKET)
self.assertEqual(blob._chunk_size, None)
blob._CHUNK_SIZE_MULTIPLE = 10
with self.assertRaises(ValueError):
blob.chunk_size = 11
def test_acl_property(self):
from gcloud.storage.acl import ObjectACL
FAKE_BUCKET = _Bucket()
blob = self._makeOne(None, bucket=FAKE_BUCKET)
acl = blob.acl
self.assertTrue(isinstance(acl, ObjectACL))
self.assertTrue(acl is blob._acl)
def test_path_no_bucket(self):
FAKE_BUCKET = object()
NAME = 'blob-name'
blob = self._makeOne(NAME, bucket=FAKE_BUCKET)
self.assertRaises(AttributeError, getattr, blob, 'path')
def test_path_no_name(self):
bucket = _Bucket()
blob = self._makeOne(None, bucket=bucket)
self.assertRaises(ValueError, getattr, blob, 'path')
def test_path_normal(self):
BLOB_NAME = 'blob-name'
bucket = _Bucket()
blob = self._makeOne(BLOB_NAME, bucket=bucket)
self.assertEqual(blob.path, '/b/name/o/%s' % BLOB_NAME)
def test_path_w_slash_in_name(self):
BLOB_NAME = 'parent/child'
bucket = _Bucket()
blob = self._makeOne(BLOB_NAME, bucket=bucket)
self.assertEqual(blob.path, '/b/name/o/parent%2Fchild')
def test_public_url(self):
BLOB_NAME = 'blob-name'
bucket = _Bucket()
blob = self._makeOne(BLOB_NAME, bucket=bucket)
self.assertEqual(blob.public_url,
'https://storage.googleapis.com/name/%s' %
BLOB_NAME)
def test_public_url_w_slash_in_name(self):
BLOB_NAME = 'parent/child'
bucket = _Bucket()
blob = self._makeOne(BLOB_NAME, bucket=bucket)
self.assertEqual(
blob.public_url,
'https://storage.googleapis.com/name/parent%2Fchild')
def _basic_generate_signed_url_helper(self, credentials=None):
from gcloud._testing import _Monkey
from gcloud.storage import blob as MUT
BLOB_NAME = 'blob-name'
EXPIRATION = '2014-10-16T20:34:37.000Z'
connection = _Connection()
client = _Client(connection)
bucket = _Bucket(client)
blob = self._makeOne(BLOB_NAME, bucket=bucket)
URI = ('http://example.com/abucket/a-blob-name?Signature=DEADBEEF'
'&Expiration=2014-10-16T20:34:37.000Z')
SIGNER = _Signer()
with _Monkey(MUT, generate_signed_url=SIGNER):
signed_uri = blob.generate_signed_url(EXPIRATION,
credentials=credentials)
self.assertEqual(signed_uri, URI)
PATH = '/name/%s' % (BLOB_NAME,)
if credentials is None:
EXPECTED_ARGS = (_Connection.credentials,)
else:
EXPECTED_ARGS = (credentials,)
EXPECTED_KWARGS = {
'api_access_endpoint': 'https://storage.googleapis.com',
'expiration': EXPIRATION,
'method': 'GET',
'resource': PATH,
'content_type': None,
'response_type': None,
'response_disposition': None,
'generation': None,
}
self.assertEqual(SIGNER._signed, [(EXPECTED_ARGS, EXPECTED_KWARGS)])
def test_generate_signed_url_w_default_method(self):
self._basic_generate_signed_url_helper()
def test_generate_signed_url_w_content_type(self):
from gcloud._testing import _Monkey
from gcloud.storage import blob as MUT
BLOB_NAME = 'blob-name'
EXPIRATION = '2014-10-16T20:34:37.000Z'
connection = _Connection()
client = _Client(connection)
bucket = _Bucket(client)
blob = self._makeOne(BLOB_NAME, bucket=bucket)
URI = ('http://example.com/abucket/a-blob-name?Signature=DEADBEEF'
'&Expiration=2014-10-16T20:34:37.000Z')
SIGNER = _Signer()
CONTENT_TYPE = "text/html"
with _Monkey(MUT, generate_signed_url=SIGNER):
signed_url = blob.generate_signed_url(EXPIRATION,
content_type=CONTENT_TYPE)
self.assertEqual(signed_url, URI)
PATH = '/name/%s' % (BLOB_NAME,)
EXPECTED_ARGS = (_Connection.credentials,)
EXPECTED_KWARGS = {
'api_access_endpoint': 'https://storage.googleapis.com',
'expiration': EXPIRATION,
'method': 'GET',
'resource': PATH,
'content_type': CONTENT_TYPE,
'response_type': None,
'response_disposition': None,
'generation': None,
}
self.assertEqual(SIGNER._signed, [(EXPECTED_ARGS, EXPECTED_KWARGS)])
def test_generate_signed_url_w_credentials(self):
credentials = object()
self._basic_generate_signed_url_helper(credentials=credentials)
def test_generate_signed_url_w_slash_in_name(self):
from gcloud._testing import _Monkey
from gcloud.storage import blob as MUT
BLOB_NAME = 'parent/child'
EXPIRATION = '2014-10-16T20:34:37.000Z'
connection = _Connection()
client = _Client(connection)
bucket = _Bucket(client)
blob = self._makeOne(BLOB_NAME, bucket=bucket)
URI = ('http://example.com/abucket/a-blob-name?Signature=DEADBEEF'
'&Expiration=2014-10-16T20:34:37.000Z')
SIGNER = _Signer()
with _Monkey(MUT, generate_signed_url=SIGNER):
signed_url = blob.generate_signed_url(EXPIRATION)
self.assertEqual(signed_url, URI)
EXPECTED_ARGS = (_Connection.credentials,)
EXPECTED_KWARGS = {
'api_access_endpoint': 'https://storage.googleapis.com',
'expiration': EXPIRATION,
'method': 'GET',
'resource': '/name/parent%2Fchild',
'content_type': None,
'response_type': None,
'response_disposition': None,
'generation': None,
}
self.assertEqual(SIGNER._signed, [(EXPECTED_ARGS, EXPECTED_KWARGS)])
def test_generate_signed_url_w_method_arg(self):
from gcloud._testing import _Monkey
from gcloud.storage import blob as MUT
BLOB_NAME = 'blob-name'
EXPIRATION = '2014-10-16T20:34:37.000Z'
connection = _Connection()
client = _Client(connection)
bucket = _Bucket(client)
blob = self._makeOne(BLOB_NAME, bucket=bucket)
URI = ('http://example.com/abucket/a-blob-name?Signature=DEADBEEF'
'&Expiration=2014-10-16T20:34:37.000Z')
SIGNER = _Signer()
with _Monkey(MUT, generate_signed_url=SIGNER):
signed_uri = blob.generate_signed_url(EXPIRATION, method='POST')
self.assertEqual(signed_uri, URI)
PATH = '/name/%s' % (BLOB_NAME,)
EXPECTED_ARGS = (_Connection.credentials,)
EXPECTED_KWARGS = {
'api_access_endpoint': 'https://storage.googleapis.com',
'expiration': EXPIRATION,
'method': 'POST',
'resource': PATH,
'content_type': None,
'response_type': None,
'response_disposition': None,
'generation': None,
}
self.assertEqual(SIGNER._signed, [(EXPECTED_ARGS, EXPECTED_KWARGS)])
def test_exists_miss(self):
from six.moves.http_client import NOT_FOUND
NONESUCH = 'nonesuch'
not_found_response = ({'status': NOT_FOUND}, b'')
connection = _Connection(not_found_response)
client = _Client(connection)
bucket = _Bucket(client)
blob = self._makeOne(NONESUCH, bucket=bucket)
self.assertFalse(blob.exists())
def test_exists_hit(self):
from six.moves.http_client import OK
BLOB_NAME = 'blob-name'
found_response = ({'status': OK}, b'')
connection = _Connection(found_response)
client = _Client(connection)
bucket = _Bucket(client)
blob = self._makeOne(BLOB_NAME, bucket=bucket)
bucket._blobs[BLOB_NAME] = 1
self.assertTrue(blob.exists())
def test_delete(self):
from six.moves.http_client import NOT_FOUND
BLOB_NAME = 'blob-name'
not_found_response = ({'status': NOT_FOUND}, b'')
connection = _Connection(not_found_response)
client = _Client(connection)
bucket = _Bucket(client)
blob = self._makeOne(BLOB_NAME, bucket=bucket)
bucket._blobs[BLOB_NAME] = 1
blob.delete()
self.assertFalse(blob.exists())
self.assertEqual(bucket._deleted, [(BLOB_NAME, None)])
def test_download_to_file_wo_media_link(self):
from six.moves.http_client import OK
from six.moves.http_client import PARTIAL_CONTENT
from io import BytesIO
BLOB_NAME = 'blob-name'
MEDIA_LINK = 'http://example.com/media/'
chunk1_response = {'status': PARTIAL_CONTENT,
'content-range': 'bytes 0-2/6'}
chunk2_response = {'status': OK,
'content-range': 'bytes 3-5/6'}
connection = _Connection(
(chunk1_response, b'abc'),
(chunk2_response, b'def'),
)
# Only the 'reload' request hits on this side: the others are done
# through the 'http' object.
reload_response = {'status': OK, 'content-type': 'application/json'}
connection._responses = [(reload_response, {"mediaLink": MEDIA_LINK})]
client = _Client(connection)
bucket = _Bucket(client)
blob = self._makeOne(BLOB_NAME, bucket=bucket)
fh = BytesIO()
blob.download_to_file(fh)
self.assertEqual(fh.getvalue(), b'abcdef')
self.assertEqual(blob.media_link, MEDIA_LINK)
def _download_to_file_helper(self, chunk_size=None):
from six.moves.http_client import OK
from six.moves.http_client import PARTIAL_CONTENT
from io import BytesIO
BLOB_NAME = 'blob-name'
chunk1_response = {'status': PARTIAL_CONTENT,
'content-range': 'bytes 0-2/6'}
chunk2_response = {'status': OK,
'content-range': 'bytes 3-5/6'}
connection = _Connection(
(chunk1_response, b'abc'),
(chunk2_response, b'def'),
)
client = _Client(connection)
bucket = _Bucket(client)
MEDIA_LINK = 'http://example.com/media/'
properties = {'mediaLink': MEDIA_LINK}
blob = self._makeOne(BLOB_NAME, bucket=bucket, properties=properties)
if chunk_size is not None:
blob._CHUNK_SIZE_MULTIPLE = 1
blob.chunk_size = chunk_size
fh = BytesIO()
blob.download_to_file(fh)
self.assertEqual(fh.getvalue(), b'abcdef')
def test_download_to_file_default(self):
self._download_to_file_helper()
def test_download_to_file_with_chunk_size(self):
self._download_to_file_helper(chunk_size=3)
def test_download_to_filename(self):
import os
import time
from six.moves.http_client import OK
from six.moves.http_client import PARTIAL_CONTENT
from gcloud._testing import _NamedTemporaryFile
BLOB_NAME = 'blob-name'
chunk1_response = {'status': PARTIAL_CONTENT,
'content-range': 'bytes 0-2/6'}
chunk2_response = {'status': OK,
'content-range': 'bytes 3-5/6'}
connection = _Connection(
(chunk1_response, b'abc'),
(chunk2_response, b'def'),
)
client = _Client(connection)
bucket = _Bucket(client)
MEDIA_LINK = 'http://example.com/media/'
properties = {'mediaLink': MEDIA_LINK,
'updated': '2014-12-06T13:13:50.690Z'}
blob = self._makeOne(BLOB_NAME, bucket=bucket, properties=properties)
blob._CHUNK_SIZE_MULTIPLE = 1
blob.chunk_size = 3
with _NamedTemporaryFile() as temp:
blob.download_to_filename(temp.name)
with open(temp.name, 'rb') as file_obj:
wrote = file_obj.read()
mtime = os.path.getmtime(temp.name)
updatedTime = time.mktime(blob.updated.timetuple())
self.assertEqual(wrote, b'abcdef')
self.assertEqual(mtime, updatedTime)
def test_download_to_filename_w_key(self):
import os
import time
from six.moves.http_client import OK
from six.moves.http_client import PARTIAL_CONTENT
from gcloud._testing import _NamedTemporaryFile
BLOB_NAME = 'blob-name'
KEY = 'aa426195405adee2c8081bb9e7e74b19'
HEADER_KEY_VALUE = 'YWE0MjYxOTU0MDVhZGVlMmM4MDgxYmI5ZTdlNzRiMTk='
HEADER_KEY_HASH_VALUE = 'V3Kwe46nKc3xLv96+iJ707YfZfFvlObta8TQcx2gpm0='
chunk1_response = {'status': PARTIAL_CONTENT,
'content-range': 'bytes 0-2/6'}
chunk2_response = {'status': OK,
'content-range': 'bytes 3-5/6'}
connection = _Connection(
(chunk1_response, b'abc'),
(chunk2_response, b'def'),
)
client = _Client(connection)
bucket = _Bucket(client)
MEDIA_LINK = 'http://example.com/media/'
properties = {'mediaLink': MEDIA_LINK,
'updated': '2014-12-06T13:13:50.690Z'}
blob = self._makeOne(BLOB_NAME, bucket=bucket, properties=properties)
blob._CHUNK_SIZE_MULTIPLE = 1
blob.chunk_size = 3
with _NamedTemporaryFile() as temp:
blob.download_to_filename(temp.name, encryption_key=KEY)
with open(temp.name, 'rb') as file_obj:
wrote = file_obj.read()
mtime = os.path.getmtime(temp.name)
updatedTime = time.mktime(blob.updated.timetuple())
rq = connection.http._requested
headers = dict(
[(x.title(), str(y)) for x, y in rq[0]['headers'].items()])
self.assertEqual(headers['X-Goog-Encryption-Algorithm'], 'AES256')
self.assertEqual(headers['X-Goog-Encryption-Key'], HEADER_KEY_VALUE)
self.assertEqual(headers['X-Goog-Encryption-Key-Sha256'],
HEADER_KEY_HASH_VALUE)
self.assertEqual(wrote, b'abcdef')
self.assertEqual(mtime, updatedTime)
def test_download_as_string(self):
from six.moves.http_client import OK
from six.moves.http_client import PARTIAL_CONTENT
BLOB_NAME = 'blob-name'
chunk1_response = {'status': PARTIAL_CONTENT,
'content-range': 'bytes 0-2/6'}
chunk2_response = {'status': OK,
'content-range': 'bytes 3-5/6'}
connection = _Connection(
(chunk1_response, b'abc'),
(chunk2_response, b'def'),
)
client = _Client(connection)
bucket = _Bucket(client)
MEDIA_LINK = 'http://example.com/media/'
properties = {'mediaLink': MEDIA_LINK}
blob = self._makeOne(BLOB_NAME, bucket=bucket, properties=properties)
blob._CHUNK_SIZE_MULTIPLE = 1
blob.chunk_size = 3
fetched = blob.download_as_string()
self.assertEqual(fetched, b'abcdef')
def test_upload_from_file_size_failure(self):
BLOB_NAME = 'blob-name'
connection = _Connection()
client = _Client(connection)
bucket = _Bucket(client)
blob = self._makeOne(BLOB_NAME, bucket=bucket)
file_obj = object()
with self.assertRaises(ValueError):
blob.upload_from_file(file_obj, size=None)
def _upload_from_file_simple_test_helper(self, properties=None,
content_type_arg=None,
expected_content_type=None,
chunk_size=5,
status=None):
from six.moves.http_client import OK
from six.moves.urllib.parse import parse_qsl
from six.moves.urllib.parse import urlsplit
from gcloud._testing import _NamedTemporaryFile
BLOB_NAME = 'blob-name'
DATA = b'ABCDEF'
if status is None:
status = OK
response = {'status': status}
connection = _Connection(
(response, b'{}'),
)
client = _Client(connection)
bucket = _Bucket(client)
blob = self._makeOne(BLOB_NAME, bucket=bucket, properties=properties)
blob._CHUNK_SIZE_MULTIPLE = 1
blob.chunk_size = chunk_size
with _NamedTemporaryFile() as temp:
with open(temp.name, 'wb') as file_obj:
file_obj.write(DATA)
with open(temp.name, 'rb') as file_obj:
blob.upload_from_file(file_obj, rewind=True,
content_type=content_type_arg)
rq = connection.http._requested
self.assertEqual(len(rq), 1)
self.assertEqual(rq[0]['method'], 'POST')
uri = rq[0]['uri']
scheme, netloc, path, qs, _ = urlsplit(uri)
self.assertEqual(scheme, 'http')
self.assertEqual(netloc, 'example.com')
self.assertEqual(path, '/b/name/o')
self.assertEqual(dict(parse_qsl(qs)),
{'uploadType': 'media', 'name': BLOB_NAME})
headers = dict(
[(x.title(), str(y)) for x, y in rq[0]['headers'].items()])
self.assertEqual(headers['Content-Length'], '6')
self.assertEqual(headers['Content-Type'], expected_content_type)
def test_upload_from_file_simple(self):
self._upload_from_file_simple_test_helper(
expected_content_type='application/octet-stream')
def test_upload_from_file_simple_not_found(self):
from six.moves.http_client import NOT_FOUND
from gcloud.exceptions import NotFound
with self.assertRaises(NotFound):
self._upload_from_file_simple_test_helper(status=NOT_FOUND)
def test_upload_from_file_simple_w_chunk_size_None(self):
self._upload_from_file_simple_test_helper(
expected_content_type='application/octet-stream',
chunk_size=None)
def test_upload_from_file_simple_with_content_type(self):
EXPECTED_CONTENT_TYPE = 'foo/bar'
self._upload_from_file_simple_test_helper(
properties={'contentType': EXPECTED_CONTENT_TYPE},
expected_content_type=EXPECTED_CONTENT_TYPE)
def test_upload_from_file_simple_with_content_type_passed(self):
EXPECTED_CONTENT_TYPE = 'foo/bar'
self._upload_from_file_simple_test_helper(
content_type_arg=EXPECTED_CONTENT_TYPE,
expected_content_type=EXPECTED_CONTENT_TYPE)
def test_upload_from_file_simple_both_content_type_sources(self):
EXPECTED_CONTENT_TYPE = 'foo/bar'
ALT_CONTENT_TYPE = 'foo/baz'
self._upload_from_file_simple_test_helper(
properties={'contentType': ALT_CONTENT_TYPE},
content_type_arg=EXPECTED_CONTENT_TYPE,
expected_content_type=EXPECTED_CONTENT_TYPE)
def test_upload_from_file_resumable(self):
from six.moves.http_client import OK
from six.moves.urllib.parse import parse_qsl
from six.moves.urllib.parse import urlsplit
from gcloud._testing import _Monkey
from gcloud._testing import _NamedTemporaryFile
from gcloud.streaming import http_wrapper
from gcloud.streaming import transfer
BLOB_NAME = 'blob-name'
UPLOAD_URL = 'http://example.com/upload/name/key'
DATA = b'ABCDEF'
loc_response = {'status': OK, 'location': UPLOAD_URL}
chunk1_response = {'status': http_wrapper.RESUME_INCOMPLETE,
'range': 'bytes 0-4'}
chunk2_response = {'status': OK}
# Need valid JSON on last response, since resumable.
connection = _Connection(
(loc_response, b''),
(chunk1_response, b''),
(chunk2_response, b'{}'),
)
client = _Client(connection)
bucket = _Bucket(client)
blob = self._makeOne(BLOB_NAME, bucket=bucket)
blob._CHUNK_SIZE_MULTIPLE = 1
blob.chunk_size = 5
# Set the threshhold low enough that we force a resumable uploada.
with _Monkey(transfer, RESUMABLE_UPLOAD_THRESHOLD=5):
with _NamedTemporaryFile() as temp:
with open(temp.name, 'wb') as file_obj:
file_obj.write(DATA)
with open(temp.name, 'rb') as file_obj:
blob.upload_from_file(file_obj, rewind=True)
rq = connection.http._requested
self.assertEqual(len(rq), 3)
# Requested[0]
headers = dict(
[(x.title(), str(y)) for x, y in rq[0].pop('headers').items()])
self.assertEqual(headers['X-Upload-Content-Length'], '6')
self.assertEqual(headers['X-Upload-Content-Type'],
'application/octet-stream')
uri = rq[0].pop('uri')
scheme, netloc, path, qs, _ = urlsplit(uri)
self.assertEqual(scheme, 'http')
self.assertEqual(netloc, 'example.com')
self.assertEqual(path, '/b/name/o')
self.assertEqual(dict(parse_qsl(qs)),
{'uploadType': 'resumable', 'name': BLOB_NAME})
self.assertEqual(rq[0], {
'method': 'POST',
'body': '',
'connection_type': None,
'redirections': 5,
})
# Requested[1]
headers = dict(
[(x.title(), str(y)) for x, y in rq[1].pop('headers').items()])
self.assertEqual(headers['Content-Range'], 'bytes 0-4/6')
self.assertEqual(rq[1], {
'method': 'PUT',
'uri': UPLOAD_URL,
'body': DATA[:5],
'connection_type': None,
'redirections': 5,
})
# Requested[2]
headers = dict(
[(x.title(), str(y)) for x, y in rq[2].pop('headers').items()])
self.assertEqual(headers['Content-Range'], 'bytes 5-5/6')
self.assertEqual(rq[2], {
'method': 'PUT',
'uri': UPLOAD_URL,
'body': DATA[5:],
'connection_type': None,
'redirections': 5,
})
def test_upload_from_file_resumable_w_error(self):
from six.moves.http_client import NOT_FOUND
from six.moves.urllib.parse import parse_qsl
from six.moves.urllib.parse import urlsplit
from gcloud._testing import _Monkey
from gcloud._testing import _NamedTemporaryFile
from gcloud.streaming import transfer
from gcloud.streaming.exceptions import HttpError
BLOB_NAME = 'blob-name'
DATA = b'ABCDEF'
loc_response = {'status': NOT_FOUND}
connection = _Connection(
(loc_response, b'{"error": "no such bucket"}'),
)
client = _Client(connection)
bucket = _Bucket(client)
blob = self._makeOne(BLOB_NAME, bucket=bucket)
blob._CHUNK_SIZE_MULTIPLE = 1
blob.chunk_size = 5
# Set the threshhold low enough that we force a resumable uploada.
with _Monkey(transfer, RESUMABLE_UPLOAD_THRESHOLD=5):
with _NamedTemporaryFile() as temp:
with open(temp.name, 'wb') as file_obj:
file_obj.write(DATA)
with open(temp.name, 'rb') as file_obj:
with self.assertRaises(HttpError):
blob.upload_from_file(file_obj, rewind=True)
rq = connection.http._requested
self.assertEqual(len(rq), 1)
# Requested[0]
headers = dict(
[(x.title(), str(y)) for x, y in rq[0].pop('headers').items()])
self.assertEqual(headers['X-Upload-Content-Length'], '6')
self.assertEqual(headers['X-Upload-Content-Type'],
'application/octet-stream')
uri = rq[0].pop('uri')
scheme, netloc, path, qs, _ = urlsplit(uri)
self.assertEqual(scheme, 'http')
self.assertEqual(netloc, 'example.com')
self.assertEqual(path, '/b/name/o')
self.assertEqual(dict(parse_qsl(qs)),
{'uploadType': 'resumable', 'name': BLOB_NAME})
self.assertEqual(rq[0], {
'method': 'POST',
'body': '',
'connection_type': None,
'redirections': 5,
})
def test_upload_from_file_w_slash_in_name(self):
from six.moves.http_client import OK
from six.moves.urllib.parse import parse_qsl
from six.moves.urllib.parse import urlsplit
from gcloud._testing import _NamedTemporaryFile
from gcloud.streaming import http_wrapper
BLOB_NAME = 'parent/child'
UPLOAD_URL = 'http://example.com/upload/name/parent%2Fchild'
DATA = b'ABCDEF'
loc_response = {'status': OK, 'location': UPLOAD_URL}
chunk1_response = {'status': http_wrapper.RESUME_INCOMPLETE,
'range': 'bytes 0-4'}
chunk2_response = {'status': OK}
connection = _Connection(
(loc_response, '{}'),
(chunk1_response, ''),
(chunk2_response, ''),
)
client = _Client(connection)
bucket = _Bucket(client)
blob = self._makeOne(BLOB_NAME, bucket=bucket)
blob._CHUNK_SIZE_MULTIPLE = 1
blob.chunk_size = 5
with _NamedTemporaryFile() as temp:
with open(temp.name, 'wb') as file_obj:
file_obj.write(DATA)
with open(temp.name, 'rb') as file_obj:
blob.upload_from_file(file_obj, rewind=True)
self.assertEqual(file_obj.tell(), len(DATA))
rq = connection.http._requested
self.assertEqual(len(rq), 1)
self.assertEqual(rq[0]['redirections'], 5)
self.assertEqual(rq[0]['body'], DATA)
self.assertEqual(rq[0]['connection_type'], None)
self.assertEqual(rq[0]['method'], 'POST')
uri = rq[0]['uri']
scheme, netloc, path, qs, _ = urlsplit(uri)
self.assertEqual(scheme, 'http')
self.assertEqual(netloc, 'example.com')
self.assertEqual(path, '/b/name/o')
self.assertEqual(dict(parse_qsl(qs)),
{'uploadType': 'media', 'name': 'parent/child'})
headers = dict(
[(x.title(), str(y)) for x, y in rq[0]['headers'].items()])
self.assertEqual(headers['Content-Length'], '6')
self.assertEqual(headers['Content-Type'], 'application/octet-stream')
def test_upload_from_filename_w_key(self):
from six.moves.http_client import OK
from six.moves.urllib.parse import parse_qsl
from six.moves.urllib.parse import urlsplit
from gcloud._testing import _NamedTemporaryFile
from gcloud.streaming import http_wrapper
BLOB_NAME = 'blob-name'
UPLOAD_URL = 'http://example.com/upload/name/key'
DATA = b'ABCDEF'
KEY = 'aa426195405adee2c8081bb9e7e74b19'
HEADER_KEY_VALUE = 'YWE0MjYxOTU0MDVhZGVlMmM4MDgxYmI5ZTdlNzRiMTk='
HEADER_KEY_HASH_VALUE = 'V3Kwe46nKc3xLv96+iJ707YfZfFvlObta8TQcx2gpm0='
EXPECTED_CONTENT_TYPE = 'foo/bar'
properties = {'contentType': EXPECTED_CONTENT_TYPE}
loc_response = {'status': OK, 'location': UPLOAD_URL}
chunk1_response = {'status': http_wrapper.RESUME_INCOMPLETE,
'range': 'bytes 0-4'}
chunk2_response = {'status': OK}
connection = _Connection(
(loc_response, '{}'),
(chunk1_response, ''),
(chunk2_response, ''),
)
client = _Client(connection)
bucket = _Bucket(client)
blob = self._makeOne(BLOB_NAME, bucket=bucket,
properties=properties)
blob._CHUNK_SIZE_MULTIPLE = 1
blob.chunk_size = 5
with _NamedTemporaryFile(suffix='.jpeg') as temp:
with open(temp.name, 'wb') as file_obj:
file_obj.write(DATA)
blob.upload_from_filename(temp.name,
content_type=EXPECTED_CONTENT_TYPE,
encryption_key=KEY)
rq = connection.http._requested
self.assertEqual(len(rq), 1)
self.assertEqual(rq[0]['method'], 'POST')
uri = rq[0]['uri']
scheme, netloc, path, qs, _ = urlsplit(uri)
self.assertEqual(scheme, 'http')
self.assertEqual(netloc, 'example.com')
self.assertEqual(path, '/b/name/o')
self.assertEqual(dict(parse_qsl(qs)),
{'uploadType': 'media', 'name': BLOB_NAME})
headers = dict(
[(x.title(), str(y)) for x, y in rq[0]['headers'].items()])
self.assertEqual(headers['X-Goog-Encryption-Algorithm'], 'AES256')
self.assertEqual(headers['X-Goog-Encryption-Key'], HEADER_KEY_VALUE)
self.assertEqual(headers['X-Goog-Encryption-Key-Sha256'],
HEADER_KEY_HASH_VALUE)
self.assertEqual(headers['Content-Length'], '6')
self.assertEqual(headers['Content-Type'], 'foo/bar')
def _upload_from_filename_test_helper(self, properties=None,
content_type_arg=None,
expected_content_type=None):
from six.moves.http_client import OK
from six.moves.urllib.parse import parse_qsl
from six.moves.urllib.parse import urlsplit
from gcloud._testing import _NamedTemporaryFile
from gcloud.streaming import http_wrapper
BLOB_NAME = 'blob-name'
UPLOAD_URL = 'http://example.com/upload/name/key'
DATA = b'ABCDEF'
loc_response = {'status': OK, 'location': UPLOAD_URL}
chunk1_response = {'status': http_wrapper.RESUME_INCOMPLETE,
'range': 'bytes 0-4'}
chunk2_response = {'status': OK}
connection = _Connection(
(loc_response, '{}'),
(chunk1_response, ''),
(chunk2_response, ''),
)
client = _Client(connection)
bucket = _Bucket(client)
blob = self._makeOne(BLOB_NAME, bucket=bucket,
properties=properties)
blob._CHUNK_SIZE_MULTIPLE = 1
blob.chunk_size = 5
with _NamedTemporaryFile(suffix='.jpeg') as temp:
with open(temp.name, 'wb') as file_obj:
file_obj.write(DATA)
blob.upload_from_filename(temp.name,
content_type=content_type_arg)
rq = connection.http._requested
self.assertEqual(len(rq), 1)
self.assertEqual(rq[0]['method'], 'POST')
uri = rq[0]['uri']
scheme, netloc, path, qs, _ = urlsplit(uri)
self.assertEqual(scheme, 'http')
self.assertEqual(netloc, 'example.com')
self.assertEqual(path, '/b/name/o')
self.assertEqual(dict(parse_qsl(qs)),
{'uploadType': 'media', 'name': BLOB_NAME})
headers = dict(
[(x.title(), str(y)) for x, y in rq[0]['headers'].items()])
self.assertEqual(headers['Content-Length'], '6')
self.assertEqual(headers['Content-Type'], expected_content_type)
def test_upload_from_filename(self):
self._upload_from_filename_test_helper(
expected_content_type='image/jpeg')
def test_upload_from_filename_with_content_type(self):
EXPECTED_CONTENT_TYPE = 'foo/bar'
self._upload_from_filename_test_helper(
properties={'contentType': EXPECTED_CONTENT_TYPE},
expected_content_type=EXPECTED_CONTENT_TYPE)
def test_upload_from_filename_with_content_type_passed(self):
EXPECTED_CONTENT_TYPE = 'foo/bar'
self._upload_from_filename_test_helper(
content_type_arg=EXPECTED_CONTENT_TYPE,
expected_content_type=EXPECTED_CONTENT_TYPE)
def test_upload_from_filename_both_content_type_sources(self):
EXPECTED_CONTENT_TYPE = 'foo/bar'
ALT_CONTENT_TYPE = 'foo/baz'
self._upload_from_filename_test_helper(
properties={'contentType': ALT_CONTENT_TYPE},
content_type_arg=EXPECTED_CONTENT_TYPE,
expected_content_type=EXPECTED_CONTENT_TYPE)
def test_upload_from_string_w_bytes(self):
from six.moves.http_client import OK
from six.moves.urllib.parse import parse_qsl
from six.moves.urllib.parse import urlsplit
from gcloud.streaming import http_wrapper
BLOB_NAME = 'blob-name'
UPLOAD_URL = 'http://example.com/upload/name/key'
DATA = b'ABCDEF'
loc_response = {'status': OK, 'location': UPLOAD_URL}
chunk1_response = {'status': http_wrapper.RESUME_INCOMPLETE,
'range': 'bytes 0-4'}
chunk2_response = {'status': OK}
connection = _Connection(
(loc_response, '{}'),
(chunk1_response, ''),
(chunk2_response, ''),
)
client = _Client(connection)
bucket = _Bucket(client)
blob = self._makeOne(BLOB_NAME, bucket=bucket)
blob._CHUNK_SIZE_MULTIPLE = 1
blob.chunk_size = 5
blob.upload_from_string(DATA)
rq = connection.http._requested
self.assertEqual(len(rq), 1)
self.assertEqual(rq[0]['method'], 'POST')
uri = rq[0]['uri']
scheme, netloc, path, qs, _ = urlsplit(uri)
self.assertEqual(scheme, 'http')
self.assertEqual(netloc, 'example.com')
self.assertEqual(path, '/b/name/o')
self.assertEqual(dict(parse_qsl(qs)),
{'uploadType': 'media', 'name': BLOB_NAME})
headers = dict(
[(x.title(), str(y)) for x, y in rq[0]['headers'].items()])
self.assertEqual(headers['Content-Length'], '6')
self.assertEqual(headers['Content-Type'], 'text/plain')
self.assertEqual(rq[0]['body'], DATA)
def test_upload_from_string_w_text(self):
from six.moves.http_client import OK
from six.moves.urllib.parse import parse_qsl
from six.moves.urllib.parse import urlsplit
from gcloud.streaming import http_wrapper
BLOB_NAME = 'blob-name'
UPLOAD_URL = 'http://example.com/upload/name/key'
DATA = u'ABCDEF\u1234'
ENCODED = DATA.encode('utf-8')
loc_response = {'status': OK, 'location': UPLOAD_URL}
chunk1_response = {'status': http_wrapper.RESUME_INCOMPLETE,
'range': 'bytes 0-4'}
chunk2_response = {'status': OK}
connection = _Connection(
(loc_response, '{}'),
(chunk1_response, ''),
(chunk2_response, ''),
)
client = _Client(connection)
bucket = _Bucket(client=client)
blob = self._makeOne(BLOB_NAME, bucket=bucket)
blob._CHUNK_SIZE_MULTIPLE = 1
blob.chunk_size = 5
blob.upload_from_string(DATA)
rq = connection.http._requested
self.assertEqual(len(rq), 1)
self.assertEqual(rq[0]['method'], 'POST')
uri = rq[0]['uri']
scheme, netloc, path, qs, _ = urlsplit(uri)
self.assertEqual(scheme, 'http')
self.assertEqual(netloc, 'example.com')
self.assertEqual(path, '/b/name/o')
self.assertEqual(dict(parse_qsl(qs)),
{'uploadType': 'media', 'name': BLOB_NAME})
headers = dict(
[(x.title(), str(y)) for x, y in rq[0]['headers'].items()])
self.assertEqual(headers['Content-Length'], str(len(ENCODED)))
self.assertEqual(headers['Content-Type'], 'text/plain')
self.assertEqual(rq[0]['body'], ENCODED)
def test_upload_from_string_text_w_key(self):
from six.moves.http_client import OK
from six.moves.urllib.parse import parse_qsl
from six.moves.urllib.parse import urlsplit
from gcloud.streaming import http_wrapper
BLOB_NAME = 'blob-name'
KEY = 'aa426195405adee2c8081bb9e7e74b19'
HEADER_KEY_VALUE = 'YWE0MjYxOTU0MDVhZGVlMmM4MDgxYmI5ZTdlNzRiMTk='
HEADER_KEY_HASH_VALUE = 'V3Kwe46nKc3xLv96+iJ707YfZfFvlObta8TQcx2gpm0='
UPLOAD_URL = 'http://example.com/upload/name/key'
DATA = u'ABCDEF\u1234'
ENCODED = DATA.encode('utf-8')
loc_response = {'status': OK, 'location': UPLOAD_URL}
chunk1_response = {'status': http_wrapper.RESUME_INCOMPLETE,
'range': 'bytes 0-4'}
chunk2_response = {'status': OK}
connection = _Connection(
(loc_response, '{}'),
(chunk1_response, ''),
(chunk2_response, ''),
)
client = _Client(connection)
bucket = _Bucket(client=client)
blob = self._makeOne(BLOB_NAME, bucket=bucket)
blob._CHUNK_SIZE_MULTIPLE = 1
blob.chunk_size = 5
blob.upload_from_string(DATA, encryption_key=KEY)
rq = connection.http._requested
self.assertEqual(len(rq), 1)
self.assertEqual(rq[0]['method'], 'POST')
uri = rq[0]['uri']
scheme, netloc, path, qs, _ = urlsplit(uri)
self.assertEqual(scheme, 'http')
self.assertEqual(netloc, 'example.com')
self.assertEqual(path, '/b/name/o')
self.assertEqual(dict(parse_qsl(qs)),
{'uploadType': 'media', 'name': BLOB_NAME})
headers = dict(
[(x.title(), str(y)) for x, y in rq[0]['headers'].items()])
self.assertEqual(headers['X-Goog-Encryption-Algorithm'], 'AES256')
self.assertEqual(headers['X-Goog-Encryption-Key'], HEADER_KEY_VALUE)
self.assertEqual(headers['X-Goog-Encryption-Key-Sha256'],
HEADER_KEY_HASH_VALUE)
self.assertEqual(headers['Content-Length'], str(len(ENCODED)))
self.assertEqual(headers['Content-Type'], 'text/plain')
self.assertEqual(rq[0]['body'], ENCODED)
def test_make_public(self):
from six.moves.http_client import OK
from gcloud.storage.acl import _ACLEntity
BLOB_NAME = 'blob-name'
permissive = [{'entity': 'allUsers', 'role': _ACLEntity.READER_ROLE}]
after = ({'status': OK}, {'acl': permissive})
connection = _Connection(after)
client = _Client(connection)
bucket = _Bucket(client=client)
blob = self._makeOne(BLOB_NAME, bucket=bucket)
blob.acl.loaded = True
blob.make_public()
self.assertEqual(list(blob.acl), permissive)
kw = connection._requested
self.assertEqual(len(kw), 1)
self.assertEqual(kw[0]['method'], 'PATCH')
self.assertEqual(kw[0]['path'], '/b/name/o/%s' % BLOB_NAME)
self.assertEqual(kw[0]['data'], {'acl': permissive})
self.assertEqual(kw[0]['query_params'], {'projection': 'full'})
def test_cache_control_getter(self):
BLOB_NAME = 'blob-name'
bucket = _Bucket()
CACHE_CONTROL = 'no-cache'
properties = {'cacheControl': CACHE_CONTROL}
blob = self._makeOne(BLOB_NAME, bucket=bucket, properties=properties)
self.assertEqual(blob.cache_control, CACHE_CONTROL)
def test_cache_control_setter(self):
BLOB_NAME = 'blob-name'
CACHE_CONTROL = 'no-cache'
bucket = _Bucket()
blob = self._makeOne(BLOB_NAME, bucket=bucket)
self.assertEqual(blob.cache_control, None)
blob.cache_control = CACHE_CONTROL
self.assertEqual(blob.cache_control, CACHE_CONTROL)
def test_component_count(self):
BUCKET = object()
COMPONENT_COUNT = 42
blob = self._makeOne('blob-name', bucket=BUCKET,
properties={'componentCount': COMPONENT_COUNT})
self.assertEqual(blob.component_count, COMPONENT_COUNT)
def test_component_count_unset(self):
BUCKET = object()
blob = self._makeOne('blob-name', bucket=BUCKET)
self.assertEqual(blob.component_count, None)
def test_component_count_string_val(self):
BUCKET = object()
COMPONENT_COUNT = 42
blob = self._makeOne(
'blob-name', bucket=BUCKET,
properties={'componentCount': str(COMPONENT_COUNT)})
self.assertEqual(blob.component_count, COMPONENT_COUNT)
def test_content_disposition_getter(self):
BLOB_NAME = 'blob-name'
bucket = _Bucket()
CONTENT_DISPOSITION = 'Attachment; filename=example.jpg'
properties = {'contentDisposition': CONTENT_DISPOSITION}
blob = self._makeOne(BLOB_NAME, bucket=bucket, properties=properties)
self.assertEqual(blob.content_disposition, CONTENT_DISPOSITION)
def test_content_disposition_setter(self):
BLOB_NAME = 'blob-name'
CONTENT_DISPOSITION = 'Attachment; filename=example.jpg'
bucket = _Bucket()
blob = self._makeOne(BLOB_NAME, bucket=bucket)
self.assertEqual(blob.content_disposition, None)
blob.content_disposition = CONTENT_DISPOSITION
self.assertEqual(blob.content_disposition, CONTENT_DISPOSITION)
def test_content_encoding_getter(self):
BLOB_NAME = 'blob-name'
bucket = _Bucket()
CONTENT_ENCODING = 'gzip'
properties = {'contentEncoding': CONTENT_ENCODING}
blob = self._makeOne(BLOB_NAME, bucket=bucket, properties=properties)
self.assertEqual(blob.content_encoding, CONTENT_ENCODING)
def test_content_encoding_setter(self):
BLOB_NAME = 'blob-name'
CONTENT_ENCODING = 'gzip'
bucket = _Bucket()
blob = self._makeOne(BLOB_NAME, bucket=bucket)
self.assertEqual(blob.content_encoding, None)
blob.content_encoding = CONTENT_ENCODING
self.assertEqual(blob.content_encoding, CONTENT_ENCODING)
def test_content_language_getter(self):
BLOB_NAME = 'blob-name'
bucket = _Bucket()
CONTENT_LANGUAGE = 'pt-BR'
properties = {'contentLanguage': CONTENT_LANGUAGE}
blob = self._makeOne(BLOB_NAME, bucket=bucket, properties=properties)
self.assertEqual(blob.content_language, CONTENT_LANGUAGE)
def test_content_language_setter(self):
BLOB_NAME = 'blob-name'
CONTENT_LANGUAGE = 'pt-BR'
bucket = _Bucket()
blob = self._makeOne(BLOB_NAME, bucket=bucket)
self.assertEqual(blob.content_language, None)
blob.content_language = CONTENT_LANGUAGE
self.assertEqual(blob.content_language, CONTENT_LANGUAGE)
def test_content_type_getter(self):
BLOB_NAME = 'blob-name'
bucket = _Bucket()
CONTENT_TYPE = 'image/jpeg'
properties = {'contentType': CONTENT_TYPE}
blob = self._makeOne(BLOB_NAME, bucket=bucket, properties=properties)
self.assertEqual(blob.content_type, CONTENT_TYPE)
def test_content_type_setter(self):
BLOB_NAME = 'blob-name'
CONTENT_TYPE = 'image/jpeg'
bucket = _Bucket()
blob = self._makeOne(BLOB_NAME, bucket=bucket)
self.assertEqual(blob.content_type, None)
blob.content_type = CONTENT_TYPE
self.assertEqual(blob.content_type, CONTENT_TYPE)
def test_crc32c_getter(self):
BLOB_NAME = 'blob-name'
bucket = _Bucket()
CRC32C = 'DEADBEEF'
properties = {'crc32c': CRC32C}
blob = self._makeOne(BLOB_NAME, bucket=bucket, properties=properties)
self.assertEqual(blob.crc32c, CRC32C)
def test_crc32c_setter(self):
BLOB_NAME = 'blob-name'
CRC32C = 'DEADBEEF'
bucket = _Bucket()
blob = self._makeOne(BLOB_NAME, bucket=bucket)
self.assertEqual(blob.crc32c, None)
blob.crc32c = CRC32C
self.assertEqual(blob.crc32c, CRC32C)
def test_etag(self):
BLOB_NAME = 'blob-name'
bucket = _Bucket()
ETAG = 'ETAG'
properties = {'etag': ETAG}
blob = self._makeOne(BLOB_NAME, bucket=bucket, properties=properties)
self.assertEqual(blob.etag, ETAG)
def test_generation(self):
BUCKET = object()
GENERATION = 42
blob = self._makeOne('blob-name', bucket=BUCKET,
properties={'generation': GENERATION})
self.assertEqual(blob.generation, GENERATION)
def test_generation_unset(self):
BUCKET = object()
blob = self._makeOne('blob-name', bucket=BUCKET)
self.assertEqual(blob.generation, None)
def test_generation_string_val(self):
BUCKET = object()
GENERATION = 42
blob = self._makeOne('blob-name', bucket=BUCKET,
properties={'generation': str(GENERATION)})
self.assertEqual(blob.generation, GENERATION)
def test_id(self):
BLOB_NAME = 'blob-name'
bucket = _Bucket()
ID = 'ID'
properties = {'id': ID}
blob = self._makeOne(BLOB_NAME, bucket=bucket, properties=properties)
self.assertEqual(blob.id, ID)
def test_md5_hash_getter(self):
BLOB_NAME = 'blob-name'
bucket = _Bucket()
MD5_HASH = 'DEADBEEF'
properties = {'md5Hash': MD5_HASH}
blob = self._makeOne(BLOB_NAME, bucket=bucket, properties=properties)
self.assertEqual(blob.md5_hash, MD5_HASH)
def test_md5_hash_setter(self):
BLOB_NAME = 'blob-name'
MD5_HASH = 'DEADBEEF'
bucket = _Bucket()
blob = self._makeOne(BLOB_NAME, bucket=bucket)
self.assertEqual(blob.md5_hash, None)
blob.md5_hash = MD5_HASH
self.assertEqual(blob.md5_hash, MD5_HASH)
def test_media_link(self):
BLOB_NAME = 'blob-name'
bucket = _Bucket()
MEDIA_LINK = 'http://example.com/media/'
properties = {'mediaLink': MEDIA_LINK}
blob = self._makeOne(BLOB_NAME, bucket=bucket, properties=properties)
self.assertEqual(blob.media_link, MEDIA_LINK)
def test_metadata_getter(self):
BLOB_NAME = 'blob-name'
bucket = _Bucket()
METADATA = {'foo': 'Foo'}
properties = {'metadata': METADATA}
blob = self._makeOne(BLOB_NAME, bucket=bucket, properties=properties)
self.assertEqual(blob.metadata, METADATA)
def test_metadata_setter(self):
BLOB_NAME = 'blob-name'
METADATA = {'foo': 'Foo'}
bucket = _Bucket()
blob = self._makeOne(BLOB_NAME, bucket=bucket)
self.assertEqual(blob.metadata, None)
blob.metadata = METADATA
self.assertEqual(blob.metadata, METADATA)
def test_metageneration(self):
BUCKET = object()
METAGENERATION = 42
blob = self._makeOne('blob-name', bucket=BUCKET,
properties={'metageneration': METAGENERATION})
self.assertEqual(blob.metageneration, METAGENERATION)
def test_metageneration_unset(self):
BUCKET = object()
blob = self._makeOne('blob-name', bucket=BUCKET)
self.assertEqual(blob.metageneration, None)
def test_metageneration_string_val(self):
BUCKET = object()
METAGENERATION = 42
blob = self._makeOne(
'blob-name', bucket=BUCKET,
properties={'metageneration': str(METAGENERATION)})
self.assertEqual(blob.metageneration, METAGENERATION)
def test_owner(self):
BLOB_NAME = 'blob-name'
bucket = _Bucket()
OWNER = {'entity': 'project-owner-12345', 'entityId': '23456'}
properties = {'owner': OWNER}
blob = self._makeOne(BLOB_NAME, bucket=bucket, properties=properties)
owner = blob.owner
self.assertEqual(owner['entity'], 'project-owner-12345')
self.assertEqual(owner['entityId'], '23456')
def test_self_link(self):
BLOB_NAME = 'blob-name'
bucket = _Bucket()
SELF_LINK = 'http://example.com/self/'
properties = {'selfLink': SELF_LINK}
blob = self._makeOne(BLOB_NAME, bucket=bucket, properties=properties)
self.assertEqual(blob.self_link, SELF_LINK)
def test_size(self):
BUCKET = object()
SIZE = 42
blob = self._makeOne('blob-name', bucket=BUCKET,
properties={'size': SIZE})
self.assertEqual(blob.size, SIZE)
def test_size_unset(self):
BUCKET = object()
blob = self._makeOne('blob-name', bucket=BUCKET)
self.assertEqual(blob.size, None)
def test_size_string_val(self):
BUCKET = object()
SIZE = 42
blob = self._makeOne('blob-name', bucket=BUCKET,
properties={'size': str(SIZE)})
self.assertEqual(blob.size, SIZE)
def test_storage_class(self):
BLOB_NAME = 'blob-name'
bucket = _Bucket()
STORAGE_CLASS = 'http://example.com/self/'
properties = {'storageClass': STORAGE_CLASS}
blob = self._makeOne(BLOB_NAME, bucket=bucket, properties=properties)
self.assertEqual(blob.storage_class, STORAGE_CLASS)
def test_time_deleted(self):
import datetime
from gcloud._helpers import _RFC3339_MICROS
from gcloud._helpers import UTC
BLOB_NAME = 'blob-name'
bucket = _Bucket()
TIMESTAMP = datetime.datetime(2014, 11, 5, 20, 34, 37, tzinfo=UTC)
TIME_DELETED = TIMESTAMP.strftime(_RFC3339_MICROS)
properties = {'timeDeleted': TIME_DELETED}
blob = self._makeOne(BLOB_NAME, bucket=bucket, properties=properties)
self.assertEqual(blob.time_deleted, TIMESTAMP)
def test_time_deleted_unset(self):
BUCKET = object()
blob = self._makeOne('blob-name', bucket=BUCKET)
self.assertEqual(blob.time_deleted, None)
def test_updated(self):
import datetime
from gcloud._helpers import _RFC3339_MICROS
from gcloud._helpers import UTC
BLOB_NAME = 'blob-name'
bucket = _Bucket()
TIMESTAMP = datetime.datetime(2014, 11, 5, 20, 34, 37, tzinfo=UTC)
UPDATED = TIMESTAMP.strftime(_RFC3339_MICROS)
properties = {'updated': UPDATED}
blob = self._makeOne(BLOB_NAME, bucket=bucket, properties=properties)
self.assertEqual(blob.updated, TIMESTAMP)
def test_updated_unset(self):
BUCKET = object()
blob = self._makeOne('blob-name', bucket=BUCKET)
self.assertEqual(blob.updated, None)
class _Responder(object):
def __init__(self, *responses):
self._responses = responses[:]
self._requested = []
def _respond(self, **kw):
self._requested.append(kw)
response, self._responses = self._responses[0], self._responses[1:]
return response
class _Connection(_Responder):
API_BASE_URL = 'http://example.com'
USER_AGENT = 'testing 1.2.3'
credentials = object()
def __init__(self, *responses):
super(_Connection, self).__init__(*responses)
self._signed = []
self.http = _HTTP(*responses)
def api_request(self, **kw):
from six.moves.http_client import NOT_FOUND
from gcloud.exceptions import NotFound
info, content = self._respond(**kw)
if info.get('status') == NOT_FOUND:
raise NotFound(info)
return content
def build_api_url(self, path, query_params=None,
api_base_url=API_BASE_URL):
from six.moves.urllib.parse import urlencode
from six.moves.urllib.parse import urlsplit
from six.moves.urllib.parse import urlunsplit
# Mimic the build_api_url interface.
qs = urlencode(query_params or {})
scheme, netloc, _, _, _ = urlsplit(api_base_url)
return urlunsplit((scheme, netloc, path, qs, ''))
class _HTTP(_Responder):
connections = {} # For google-apitools debugging.
def request(self, uri, method, headers, body, **kw):
if hasattr(body, 'read'):
body = body.read()
return self._respond(uri=uri, method=method, headers=headers,
body=body, **kw)
class _Bucket(object):
path = '/b/name'
name = 'name'
def __init__(self, client=None):
if client is None:
connection = _Connection()
client = _Client(connection)
self.client = client
self._blobs = {}
self._copied = []
self._deleted = []
def delete_blob(self, blob_name, client=None):
del self._blobs[blob_name]
self._deleted.append((blob_name, client))
class _Signer(object):
def __init__(self):
self._signed = []
def __call__(self, *args, **kwargs):
self._signed.append((args, kwargs))
return ('http://example.com/abucket/a-blob-name?Signature=DEADBEEF'
'&Expiration=%s' % kwargs.get('expiration'))
class _Client(object):
def __init__(self, connection):
self._connection = connection
@property
def connection(self):
return self._connection