Allow to set content-type for uploading blobs

Change-Id: I97446773544c05cb700385ab60ca7bd5f0a611b5
This commit is contained in:
Mike Fedosin 2016-09-22 22:05:38 +03:00
parent 5cf1030ca8
commit b3394f4b52
6 changed files with 78 additions and 14 deletions

View File

@ -62,21 +62,29 @@ def _chunk_body(body):
def _set_request_params(kwargs_params):
"""Handle the common parameters used to send the request."""
data = kwargs_params.pop('data', None)
params = copy.deepcopy(kwargs_params)
headers = params.get('headers', {})
content_type = headers.get('Content-Type', 'application/json')
content_type = headers.get('Content-Type')
stream = params.get("stream", False)
if data is not None and not isinstance(data, six.string_types):
if content_type.startswith('application/json'):
data = jsonutils.dumps(data)
if content_type == 'application/octet-stream':
if stream:
if data is not None:
data = _chunk_body(data)
content_type = content_type or 'application/octet-stream'
elif data is not None and not isinstance(data, six.string_types):
try:
data = jsonutils.dumps(data)
except TypeError:
raise exc.HTTPBadRequest("json is malformed.")
params['data'] = data
headers.update({'Content-Type': content_type})
headers.update(
{'Content-Type': content_type or 'application/json'})
params['headers'] = headers
params['stream'] = content_type == 'application/octet-stream'
params['stream'] = stream
return params

View File

@ -62,6 +62,12 @@ class UploadBlob(command.ShowOne):
metavar='<BLOB_PROPERTY>',
help='Name of the blob field.'
)
parser.add_argument(
'--content-type',
metavar='<CONTENT_TYPE>',
default='application/octet-stream',
help='Content-type of the blob.'
)
parser.add_argument(
'--progress',
help='Show download progress bar.'
@ -83,8 +89,8 @@ class UploadBlob(command.ShowOne):
blob = progressbar.VerboseFileWrapper(blob, file_size)
client.artifacts.upload_blob(parsed_args.id,
parsed_args.blob_property,
blob,
parsed_args.blob_property, blob,
content_type=parsed_args.content_type,
type_name=parsed_args.type_name)
data = client.artifacts.get(parsed_args.id,

View File

@ -135,6 +135,38 @@ class TestUploadBlob(TestBlobs):
with testtools.ExpectedException(SystemExit):
self.cmd.take_action(parsed_args)
def test_upload_with_custom_content_type(self):
exp_data = ('template', 'application/x-yaml', False,
'35d83e8eedfbdb87ff97d1f2761f8ebf',
'942854360eeec1335537702399c5aed940401602',
'd8a7834fc6652f316322d80196f6dcf2'
'94417030e37c15412e4deb7a67a367dd',
594, 'active', 'fake_url')
mocked_get = {
"status": "active",
"url": "fake_url",
"md5": "35d83e8eedfbdb87ff97d1f2761f8ebf",
"sha1": "942854360eeec1335537702399c5aed940401602",
"sha256": "d8a7834fc6652f316322d80196f6dcf2"
"94417030e37c15412e4deb7a67a367dd",
"external": False,
"content_type": "application/x-yaml",
"size": 594}
self.app.client_manager.artifact.artifacts.get = \
lambda id, type_name: {'template': mocked_get}
arglist = ['tosca_templates',
'fc15c365-d4f9-4b8b-a090-d9e230f1f6ba',
'--file', '/path/to/file',
'--content-type', 'application/x-yaml']
verify = [('type_name', 'tosca_templates')]
parsed_args = self.check_parser(self.cmd, arglist, verify)
columns, data = self.cmd.take_action(parsed_args)
self.assertEqual(self.COLUMNS, columns)
self.assertEqual(exp_data, data)
def test_upload_blob_with_blob_prop(self):
exp_data = ('blob', 'application/octet-stream', False,
'35d83e8eedfbdb87ff97d1f2761f8ebf',

View File

@ -277,6 +277,23 @@ class TestController(testtools.TestCase):
'data')]
self.assertEqual(expect, self.api.calls)
def test_upload_blob_custom_content_type(self):
art_id = '3a4560a1-e585-443e-9b39-553b46ec92a3'
self.controller.upload_blob(artifact_id=art_id,
type_name='sample_artifact',
blob_property='blob',
data='{"a":"b"}',
content_type='application/json',)
exp_headers = {
'Content-Type': 'application/json'
}
expect = [('PUT', '/artifacts/sample_artifact/%s/blob' % art_id,
exp_headers,
{"a": "b"})]
self.assertEqual(expect, self.api.calls)
def test_download_blob(self):
art_id = '3a4560a1-e585-443e-9b39-553b46ec92a3'
self.controller.download_blob(artifact_id=art_id,

View File

@ -26,7 +26,7 @@ class FakeAPI(object):
self.calls = []
def _request(self, method, url, headers=None, data=None,
content_length=None):
content_length=None, **kwargs):
call = build_call_record(method, sort_url_by_query_keys(url),
headers or {}, data)
if content_length is not None:
@ -210,5 +210,4 @@ def build_call_record(method, url, headers, data):
data = json.loads(data)
except ValueError:
return (method, url, headers or {}, data)
data = [sorted(d.items()) for d in data]
return (method, url, headers or {}, data)

View File

@ -194,16 +194,18 @@ class Controller(object):
url = '/artifacts/%s/%s' % (type_name, artifact_id)
self.http_client.delete(url)
def upload_blob(self, artifact_id, blob_property, data, type_name=None):
def upload_blob(self, artifact_id, blob_property, data, type_name=None,
content_type=None):
"""Upload blob data.
:param artifact_id: ID of the artifact to download a blob
:param blob_property: blob property name
"""
content_type = content_type or 'application/octet-stream'
type_name = self._check_type_name(type_name)
hdrs = {'Content-Type': 'application/octet-stream'}
hdrs = {'Content-Type': content_type}
url = '/artifacts/%s/%s/%s' % (type_name, artifact_id, blob_property)
self.http_client.put(url, headers=hdrs, data=data)
self.http_client.put(url, headers=hdrs, data=data, stream=True)
def download_blob(self, artifact_id, blob_property, type_name=None,
do_checksum=True):