From 47f673ed9f8652a3e19ec12a03196e2fa79ef92a Mon Sep 17 00:00:00 2001 From: Jude Job <judeopenstack@gmail.com> Date: Sat, 9 Jan 2016 18:49:17 +0530 Subject: [PATCH] Error with uploading large object includes unicode path This patch include a test case to test unicode path. Change-Id: I7697679f0034ce65b068791d7d5145286d992bd1 Closes-Bug: #1532096 --- swiftclient/service.py | 3 +- tests/unit/test_service.py | 68 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/swiftclient/service.py b/swiftclient/service.py index 8df13897..bba9583f 100644 --- a/swiftclient/service.py +++ b/swiftclient/service.py @@ -1909,7 +1909,8 @@ class SwiftService(object): res['manifest_response_dict'] = mr else: new_object_manifest = '%s/%s/%s/%s/%s/' % ( - quote(seg_container), quote(obj), + quote(seg_container.encode('utf8')), + quote(obj.encode('utf8')), put_headers['x-object-meta-mtime'], full_size, options['segment_size']) if old_manifest and old_manifest.rstrip('/') == \ diff --git a/tests/unit/test_service.py b/tests/unit/test_service.py index 003a51f8..33176773 100644 --- a/tests/unit/test_service.py +++ b/tests/unit/test_service.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # Copyright (c) 2014 OpenStack Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -12,6 +13,7 @@ # implied. # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import unicode_literals import mock import os import six @@ -853,6 +855,72 @@ class TestService(testtools.TestCase): class TestServiceUpload(_TestServiceBase): + def test_upload_object_job_file_with_unicode_path(self): + # Uploading a file results in the file object being wrapped in a + # LengthWrapper. This test sets the options in such a way that much + # of _upload_object_job is skipped bringing the critical path down + # to around 60 lines to ease testing. + with tempfile.NamedTemporaryFile() as f: + f.write(b'a' * 30) + f.flush() + expected_r = { + 'action': 'upload_object', + 'attempts': 2, + 'container': 'test_c', + 'headers': {}, + 'large_object': True, + 'object': 'テスト/dummy.dat', + 'manifest_response_dict': {}, + 'segment_results': [{'action': 'upload_segment', + 'success': True}] * 3, + 'status': 'uploaded', + 'success': True, + } + expected_mtime = float(os.path.getmtime(f.name)) + + mock_conn = mock.Mock() + mock_conn.put_object.return_value = '' + type(mock_conn).attempts = mock.PropertyMock(return_value=2) + + s = SwiftService() + with mock.patch.object(s, '_upload_segment_job') as mock_job: + mock_job.return_value = { + 'action': 'upload_segment', + 'success': True} + + r = s._upload_object_job(conn=mock_conn, + container='test_c', + source=f.name, + obj='テスト/dummy.dat', + options={'changed': False, + 'skip_identical': False, + 'leave_segments': True, + 'header': '', + 'segment_size': 10, + 'segment_container': None, + 'use_slo': False, + 'checksum': True}) + + mtime = float(r['headers']['x-object-meta-mtime']) + self.assertAlmostEqual(mtime, expected_mtime, delta=0.5) + del r['headers']['x-object-meta-mtime'] + + self.assertEqual( + 'test_c_segments/%E3%83%86%E3%82%B9%E3%83%88/dummy.dat/' + + '%f/30/10/' % mtime, r['headers']['x-object-manifest']) + del r['headers']['x-object-manifest'] + + self.assertEqual(r['path'], f.name) + del r['path'] + + self._assertDictEqual(r, expected_r) + self.assertEqual(mock_conn.put_object.call_count, 1) + mock_conn.put_object.assert_called_with('test_c', 'テスト/dummy.dat', + '', + content_length=0, + headers={}, + response_dict={}) + def test_upload_segment_job(self): with tempfile.NamedTemporaryFile() as f: f.write(b'a' * 10)