summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--swiftclient/service.py35
-rw-r--r--tests/unit/test_service.py111
2 files changed, 129 insertions, 17 deletions
diff --git a/swiftclient/service.py b/swiftclient/service.py
index 281947e..a964d4d 100644
--- a/swiftclient/service.py
+++ b/swiftclient/service.py
@@ -313,36 +313,37 @@ class _SwiftReader(object):
self._actual_md5 = None
self._expected_etag = headers.get('etag')
- if 'x-object-manifest' not in headers and \
- 'x-static-large-object' not in headers:
- self.actual_md5 = md5()
+ if ('x-object-manifest' not in headers
+ and 'x-static-large-object' not in headers):
+ self._actual_md5 = md5()
if 'content-length' in headers:
- self._content_length = int(headers.get('content-length'))
+ try:
+ self._content_length = int(headers.get('content-length'))
+ except ValueError:
+ raise SwiftError('content-length header must be an integer')
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
- if self._actual_md5 is not None:
+ if self._actual_md5 and self._expected_etag:
etag = self._actual_md5.hexdigest()
if etag != self._expected_etag:
- raise SwiftError(
- 'Error downloading %s: md5sum != etag, %s != %s' %
- (self._path, etag, self._expected_etag)
- )
+ raise SwiftError('Error downloading {0}: md5sum != etag, '
+ '{1} != {2}'.format(
+ self._path, etag, self._expected_etag))
- if self._content_length is not None and \
- self._actual_read != self._content_length:
- raise SwiftError(
- 'Error downloading %s: read_length != content_length, '
- '%d != %d' % (self._path, self._actual_read,
- self._content_length)
- )
+ if (self._content_length is not None
+ and self._actual_read != self._content_length):
+ raise SwiftError('Error downloading {0}: read_length != '
+ 'content_length, {1:d} != {2:d}'.format(
+ self._path, self._actual_read,
+ self._content_length))
def buffer(self):
for chunk in self._body:
- if self._actual_md5 is not None:
+ if self._actual_md5:
self._actual_md5.update(chunk)
self._actual_read += len(chunk)
yield chunk
diff --git a/tests/unit/test_service.py b/tests/unit/test_service.py
index 53867ae..5211456 100644
--- a/tests/unit/test_service.py
+++ b/tests/unit/test_service.py
@@ -14,8 +14,119 @@
# limitations under the License.
import testtools
+from hashlib import md5
from swiftclient.service import SwiftService, SwiftError
+import swiftclient
+
+
+class TestSwiftPostObject(testtools.TestCase):
+
+ def setUp(self):
+ self.spo = swiftclient.service.SwiftPostObject
+ super(TestSwiftPostObject, self).setUp()
+
+ def test_create(self):
+ spo = self.spo('obj_name')
+
+ self.assertEqual(spo.object_name, 'obj_name')
+ self.assertEqual(spo.options, None)
+
+ def test_create_with_invalid_name(self):
+ # empty strings are not allowed as names
+ self.assertRaises(SwiftError, self.spo, '')
+
+ # names cannot be anything but strings
+ self.assertRaises(SwiftError, self.spo, 1)
+
+
+class TestSwiftReader(testtools.TestCase):
+
+ def setUp(self):
+ self.sr = swiftclient.service._SwiftReader
+ super(TestSwiftReader, self).setUp()
+ self.md5_type = type(md5())
+
+ def test_create(self):
+ sr = self.sr('path', 'body', {})
+
+ self.assertEqual(sr._path, 'path')
+ self.assertEqual(sr._body, 'body')
+ self.assertEqual(sr._content_length, None)
+ self.assertEqual(sr._expected_etag, None)
+
+ self.assertNotEqual(sr._actual_md5, None)
+ self.assertTrue(isinstance(sr._actual_md5, self.md5_type))
+
+ def test_create_with_large_object_headers(self):
+ # md5 should not be initalized if large object headers are present
+ sr = self.sr('path', 'body', {'x-object-manifest': 'test'})
+ self.assertEqual(sr._path, 'path')
+ self.assertEqual(sr._body, 'body')
+ self.assertEqual(sr._content_length, None)
+ self.assertEqual(sr._expected_etag, None)
+ self.assertEqual(sr._actual_md5, None)
+
+ sr = self.sr('path', 'body', {'x-static-large-object': 'test'})
+ self.assertEqual(sr._path, 'path')
+ self.assertEqual(sr._body, 'body')
+ self.assertEqual(sr._content_length, None)
+ self.assertEqual(sr._expected_etag, None)
+ self.assertEqual(sr._actual_md5, None)
+
+ def test_create_with_content_length(self):
+ sr = self.sr('path', 'body', {'content-length': 5})
+
+ self.assertEqual(sr._path, 'path')
+ self.assertEqual(sr._body, 'body')
+ self.assertEqual(sr._content_length, 5)
+ self.assertEqual(sr._expected_etag, None)
+
+ self.assertNotEqual(sr._actual_md5, None)
+ self.assertTrue(isinstance(sr._actual_md5, self.md5_type))
+
+ # Check Contentlength raises error if it isnt an integer
+ self.assertRaises(SwiftError, self.sr, 'path', 'body',
+ {'content-length': 'notanint'})
+
+ def test_context_usage(self):
+ def _context(sr):
+ with sr:
+ pass
+
+ sr = self.sr('path', 'body', {})
+ _context(sr)
+
+ # Check error is raised if expected etag doesnt match calculated md5.
+ # md5 for a SwiftReader that has done nothing is
+ # d41d8cd98f00b204e9800998ecf8427e i.e md5 of nothing
+ sr = self.sr('path', 'body', {'etag': 'doesntmatch'})
+ self.assertRaises(SwiftError, _context, sr)
+
+ sr = self.sr('path', 'body',
+ {'etag': 'd41d8cd98f00b204e9800998ecf8427e'})
+ _context(sr)
+
+ # Check error is raised if SwiftReader doesnt read the same length
+ # as the content length it is created with
+ sr = self.sr('path', 'body', {'content-length': 5})
+ self.assertRaises(SwiftError, _context, sr)
+
+ sr = self.sr('path', 'body', {'content-length': 5})
+ sr._actual_read = 5
+ _context(sr)
+
+ def test_buffer(self):
+ # md5 = 97ac82a5b825239e782d0339e2d7b910
+ mock_buffer_content = ['abc'.encode()] * 3
+
+ sr = self.sr('path', mock_buffer_content, {})
+ for x in sr.buffer():
+ pass
+
+ self.assertEqual(sr._actual_read, 9)
+ self.assertEqual(sr._actual_md5.hexdigest(),
+ '97ac82a5b825239e782d0339e2d7b910')
class TestService(testtools.TestCase):