Object Creation Assertion, everywhare
For testing purpose, we should assert the sanity of Object Creation with ETag. This patch produces a way to assert the object etag and apply it to the functional tests. Change-Id: I659ef0d9fa3104392876e23ef699cc9f310b8d85
This commit is contained in:
@@ -37,9 +37,15 @@ class TestSwift3Object(Swift3FunctionalTestCase):
|
||||
self.bucket = 'bucket'
|
||||
self.conn.make_request('PUT', self.bucket)
|
||||
|
||||
def _assertObjectEtag(self, bucket, obj, etag):
|
||||
status, headers, _ = self.conn.make_request('HEAD', bucket, obj)
|
||||
self.assertEquals(status, 200) # sanity
|
||||
assert_common_response_headers(self, headers, etag)
|
||||
|
||||
def test_object(self):
|
||||
obj = 'object'
|
||||
content = 'abc123'
|
||||
etag = md5(content).hexdigest()
|
||||
|
||||
# PUT Object
|
||||
status, headers, body = \
|
||||
@@ -47,14 +53,17 @@ class TestSwift3Object(Swift3FunctionalTestCase):
|
||||
self.assertEquals(status, 200)
|
||||
|
||||
assert_common_response_headers(self, headers)
|
||||
self.assertTrue(headers['etag'] is not None)
|
||||
self.assertTrue('content-length' in headers) # sanity
|
||||
self.assertEquals(headers['content-length'], '0')
|
||||
self._assertObjectEtag(self.bucket, obj, etag)
|
||||
|
||||
# PUT Object Copy
|
||||
self.conn.make_request('PUT', 'dst_bucket')
|
||||
dst_bucket = 'dst_bucket'
|
||||
dst_obj = 'dst_obj'
|
||||
self.conn.make_request('PUT', dst_bucket)
|
||||
headers = {'x-amz-copy-source': '/%s/%s' % (self.bucket, obj)}
|
||||
status, headers, body = \
|
||||
self.conn.make_request('PUT', 'dst_bucket', 'dst_obj',
|
||||
self.conn.make_request('PUT', dst_bucket, dst_obj,
|
||||
headers=headers)
|
||||
self.assertEquals(status, 200)
|
||||
|
||||
@@ -63,16 +72,18 @@ class TestSwift3Object(Swift3FunctionalTestCase):
|
||||
|
||||
elem = fromstring(body, 'CopyObjectResult')
|
||||
self.assertTrue(elem.find('LastModified').text is not None)
|
||||
# TODO: assert LastModified value
|
||||
self.assertTrue(elem.find('ETag').text is not None)
|
||||
self.assertEquals(etag, elem.find('ETag').text.strip('"'))
|
||||
self._assertObjectEtag(dst_bucket, dst_obj, etag)
|
||||
|
||||
# GET Object
|
||||
status, headers, body = \
|
||||
self.conn.make_request('GET', self.bucket, obj)
|
||||
self.assertEquals(status, 200)
|
||||
|
||||
assert_common_response_headers(self, headers)
|
||||
assert_common_response_headers(self, headers, etag)
|
||||
self.assertTrue(headers['last-modified'] is not None)
|
||||
self.assertTrue(headers['etag'] is not None)
|
||||
self.assertTrue(headers['content-type'] is not None)
|
||||
self.assertEquals(headers['content-length'], str(len(content)))
|
||||
|
||||
@@ -81,17 +92,15 @@ class TestSwift3Object(Swift3FunctionalTestCase):
|
||||
self.conn.make_request('HEAD', self.bucket, obj)
|
||||
self.assertEquals(status, 200)
|
||||
|
||||
assert_common_response_headers(self, headers)
|
||||
assert_common_response_headers(self, headers, etag)
|
||||
self.assertTrue(headers['last-modified'] is not None)
|
||||
self.assertTrue(headers['etag'] is not None)
|
||||
self.assertTrue(headers['content-type'] is not None)
|
||||
self.assertTrue('content-type' in headers)
|
||||
self.assertEquals(headers['content-length'], str(len(content)))
|
||||
|
||||
# DELETE Object
|
||||
status, headers, body = \
|
||||
self.conn.make_request('DELETE', self.bucket, obj)
|
||||
self.assertEquals(status, 204)
|
||||
|
||||
assert_common_response_headers(self, headers)
|
||||
|
||||
def test_put_object_error(self):
|
||||
@@ -190,25 +199,33 @@ class TestSwift3Object(Swift3FunctionalTestCase):
|
||||
|
||||
def test_put_object_content_encoding(self):
|
||||
obj = 'object'
|
||||
etag = md5().hexdigest()
|
||||
headers = {'Content-Encoding': 'gzip'}
|
||||
status, headers, body = \
|
||||
self.conn.make_request('PUT', self.bucket, obj, headers)
|
||||
self.assertEquals(status, 200)
|
||||
status, headers, body = \
|
||||
self.conn.make_request('HEAD', self.bucket, obj)
|
||||
self.assertTrue('content-encoding' in headers) # sanity
|
||||
self.assertEquals(headers['content-encoding'], 'gzip')
|
||||
assert_common_response_headers(self, headers)
|
||||
self._assertObjectEtag(self.bucket, obj, etag)
|
||||
|
||||
def test_put_object_content_md5(self):
|
||||
obj = 'object'
|
||||
content = 'abcdefghij'
|
||||
etag = md5(content).hexdigest()
|
||||
headers = {'Content-MD5': calculate_md5(content)}
|
||||
status, headers, body = \
|
||||
self.conn.make_request('PUT', self.bucket, obj, headers, content)
|
||||
self.assertEquals(status, 200)
|
||||
assert_common_response_headers(self, headers)
|
||||
self._assertObjectEtag(self.bucket, obj, etag)
|
||||
|
||||
def test_put_object_content_type(self):
|
||||
obj = 'object'
|
||||
content = 'abcdefghij'
|
||||
etag = md5(content).hexdigest()
|
||||
headers = {'Content-Type': 'text/plain'}
|
||||
status, headers, body = \
|
||||
self.conn.make_request('PUT', self.bucket, obj, headers, content)
|
||||
@@ -216,18 +233,24 @@ class TestSwift3Object(Swift3FunctionalTestCase):
|
||||
status, headers, body = \
|
||||
self.conn.make_request('HEAD', self.bucket, obj)
|
||||
self.assertEquals(headers['content-type'], 'text/plain')
|
||||
assert_common_response_headers(self, headers)
|
||||
self._assertObjectEtag(self.bucket, obj, etag)
|
||||
|
||||
def test_put_object_expect(self):
|
||||
obj = 'object'
|
||||
content = 'abcdefghij'
|
||||
etag = md5(content).hexdigest()
|
||||
headers = {'Expect': '100-continue'}
|
||||
status, headers, body = \
|
||||
self.conn.make_request('PUT', self.bucket, obj, headers, content)
|
||||
self.assertEquals(status, 200)
|
||||
assert_common_response_headers(self, headers)
|
||||
self._assertObjectEtag(self.bucket, obj, etag)
|
||||
|
||||
def test_put_object_metadata(self):
|
||||
obj = 'object'
|
||||
content = 'abcdefghij'
|
||||
etag = md5(content).hexdigest()
|
||||
headers = {'X-Amz-Meta-Bar': 'foo', 'X-Amz-Meta-Bar2': 'foo2'}
|
||||
status, headers, body = \
|
||||
self.conn.make_request('PUT', self.bucket, obj, headers, content)
|
||||
@@ -236,26 +259,26 @@ class TestSwift3Object(Swift3FunctionalTestCase):
|
||||
self.conn.make_request('HEAD', self.bucket, obj)
|
||||
self.assertEquals(headers['x-amz-meta-bar'], 'foo')
|
||||
self.assertEquals(headers['x-amz-meta-bar2'], 'foo2')
|
||||
assert_common_response_headers(self, headers)
|
||||
self._assertObjectEtag(self.bucket, obj, etag)
|
||||
|
||||
def test_put_object_storage_class(self):
|
||||
obj = 'object'
|
||||
content = 'abcdefghij'
|
||||
etag = md5(content).hexdigest()
|
||||
headers = {'X-Amz-Storage-Class': 'STANDARD'}
|
||||
status, headers, body = \
|
||||
self.conn.make_request('PUT', self.bucket, obj, headers, content)
|
||||
self.assertEquals(status, 200)
|
||||
assert_common_response_headers(self, headers)
|
||||
self._assertObjectEtag(self.bucket, obj, etag)
|
||||
|
||||
def test_put_object_copy_source(self):
|
||||
obj = 'object'
|
||||
content = 'abcdefghij'
|
||||
content_md5 = md5(content).hexdigest()
|
||||
etag = md5(content).hexdigest()
|
||||
self.conn.make_request('PUT', self.bucket, obj, body=content)
|
||||
|
||||
def assertCopiedObject(bucket, obj):
|
||||
status, headers, _ = self.conn.make_request('HEAD', bucket, obj)
|
||||
self.assertEquals(status, 200) # sanity
|
||||
self.assertEquals(content_md5, headers['etag'].strip('"'))
|
||||
|
||||
dst_bucket = 'dst_bucket'
|
||||
dst_obj = 'dst_object'
|
||||
self.conn.make_request('PUT', dst_bucket)
|
||||
@@ -265,14 +288,16 @@ class TestSwift3Object(Swift3FunctionalTestCase):
|
||||
status, headers, body = \
|
||||
self.conn.make_request('PUT', dst_bucket, dst_obj, headers)
|
||||
self.assertEquals(status, 200)
|
||||
assertCopiedObject(dst_bucket, dst_obj)
|
||||
assert_common_response_headers(self, headers)
|
||||
self._assertObjectEtag(dst_bucket, dst_obj, etag)
|
||||
|
||||
# /src/src -> /src/dst
|
||||
headers = {'X-Amz-Copy-Source': '/%s/%s' % (self.bucket, obj)}
|
||||
status, headers, body = \
|
||||
self.conn.make_request('PUT', self.bucket, dst_obj, headers)
|
||||
self.assertEquals(status, 200)
|
||||
assertCopiedObject(self.bucket, dst_obj)
|
||||
assert_common_response_headers(self, headers)
|
||||
self._assertObjectEtag(self.bucket, dst_obj, etag)
|
||||
|
||||
# /src/src -> /src/src
|
||||
# need changes to copy itself (e.g. metadata)
|
||||
@@ -282,7 +307,8 @@ class TestSwift3Object(Swift3FunctionalTestCase):
|
||||
status, headers, body = \
|
||||
self.conn.make_request('PUT', self.bucket, obj, headers)
|
||||
self.assertEquals(status, 200)
|
||||
assertCopiedObject(self.bucket, obj)
|
||||
self._assertObjectEtag(self.bucket, obj, etag)
|
||||
assert_common_response_headers(self, headers)
|
||||
|
||||
def test_put_object_copy_metadata_directive(self):
|
||||
obj = 'object'
|
||||
@@ -298,15 +324,16 @@ class TestSwift3Object(Swift3FunctionalTestCase):
|
||||
status, headers, body = \
|
||||
self.conn.make_request('PUT', dst_bucket, dst_obj, headers)
|
||||
self.assertEquals(status, 200)
|
||||
assert_common_response_headers(self, headers)
|
||||
status, headers, body = \
|
||||
self.conn.make_request('HEAD', dst_bucket, dst_obj)
|
||||
self.assertEquals(headers['x-amz-meta-test'], 'dst')
|
||||
self.conn.make_request('DELETE', dst_bucket, dst_obj)
|
||||
|
||||
def test_put_object_copy_source_if_modified_since(self):
|
||||
obj = 'object'
|
||||
dst_bucket = 'dst_bucket'
|
||||
dst_obj = 'dst_object'
|
||||
etag = md5().hexdigest()
|
||||
self.conn.make_request('PUT', self.bucket, obj)
|
||||
self.conn.make_request('PUT', dst_bucket)
|
||||
|
||||
@@ -319,11 +346,14 @@ class TestSwift3Object(Swift3FunctionalTestCase):
|
||||
status, headers, body = \
|
||||
self.conn.make_request('PUT', dst_bucket, dst_obj, headers=headers)
|
||||
self.assertEquals(status, 200)
|
||||
assert_common_response_headers(self, headers)
|
||||
self._assertObjectEtag(self.bucket, obj, etag)
|
||||
|
||||
def test_put_object_copy_source_if_unmodified_since(self):
|
||||
obj = 'object'
|
||||
dst_bucket = 'dst_bucket'
|
||||
dst_obj = 'dst_object'
|
||||
etag = md5().hexdigest()
|
||||
self.conn.make_request('PUT', self.bucket, obj)
|
||||
self.conn.make_request('PUT', dst_bucket)
|
||||
|
||||
@@ -336,28 +366,33 @@ class TestSwift3Object(Swift3FunctionalTestCase):
|
||||
status, headers, body = \
|
||||
self.conn.make_request('PUT', dst_bucket, dst_obj, headers=headers)
|
||||
self.assertEquals(status, 200)
|
||||
assert_common_response_headers(self, headers)
|
||||
self._assertObjectEtag(self.bucket, obj, etag)
|
||||
|
||||
def test_put_object_copy_source_if_match(self):
|
||||
obj = 'object'
|
||||
dst_bucket = 'dst_bucket'
|
||||
dst_obj = 'dst_object'
|
||||
etag = md5().hexdigest()
|
||||
self.conn.make_request('PUT', self.bucket, obj)
|
||||
self.conn.make_request('PUT', dst_bucket)
|
||||
|
||||
status, headers, body = \
|
||||
self.conn.make_request('HEAD', self.bucket, obj)
|
||||
etag = headers['etag']
|
||||
|
||||
headers = {'X-Amz-Copy-Source': '/%s/%s' % (self.bucket, obj),
|
||||
'X-Amz-Copy-Source-If-Match': etag}
|
||||
status, headers, body = \
|
||||
self.conn.make_request('PUT', dst_bucket, dst_obj, headers=headers)
|
||||
self.assertEquals(status, 200)
|
||||
assert_common_response_headers(self, headers)
|
||||
self._assertObjectEtag(self.bucket, obj, etag)
|
||||
|
||||
def test_put_object_copy_source_if_none_match(self):
|
||||
obj = 'object'
|
||||
dst_bucket = 'dst_bucket'
|
||||
dst_obj = 'dst_object'
|
||||
etag = md5().hexdigest()
|
||||
self.conn.make_request('PUT', self.bucket, obj)
|
||||
self.conn.make_request('PUT', dst_bucket)
|
||||
|
||||
@@ -366,6 +401,8 @@ class TestSwift3Object(Swift3FunctionalTestCase):
|
||||
status, headers, body = \
|
||||
self.conn.make_request('PUT', dst_bucket, dst_obj, headers=headers)
|
||||
self.assertEquals(status, 200)
|
||||
assert_common_response_headers(self, headers)
|
||||
self._assertObjectEtag(self.bucket, obj, etag)
|
||||
|
||||
def test_get_object_response_content_type(self):
|
||||
obj = 'obj'
|
||||
@@ -375,6 +412,7 @@ class TestSwift3Object(Swift3FunctionalTestCase):
|
||||
status, headers, body = \
|
||||
self.conn.make_request('GET', self.bucket, obj, query=query)
|
||||
self.assertEquals(status, 200)
|
||||
assert_common_response_headers(self, headers)
|
||||
self.assertEquals(headers['content-type'], 'text/plain')
|
||||
|
||||
def test_get_object_response_content_language(self):
|
||||
@@ -385,6 +423,7 @@ class TestSwift3Object(Swift3FunctionalTestCase):
|
||||
status, headers, body = \
|
||||
self.conn.make_request('GET', self.bucket, obj, query=query)
|
||||
self.assertEquals(status, 200)
|
||||
assert_common_response_headers(self, headers)
|
||||
self.assertEquals(headers['content-language'], 'en')
|
||||
|
||||
def test_get_object_response_cache_control(self):
|
||||
@@ -395,6 +434,7 @@ class TestSwift3Object(Swift3FunctionalTestCase):
|
||||
status, headers, body = \
|
||||
self.conn.make_request('GET', self.bucket, obj, query=query)
|
||||
self.assertEquals(status, 200)
|
||||
assert_common_response_headers(self, headers)
|
||||
self.assertEquals(headers['cache-control'], 'private')
|
||||
|
||||
def test_get_object_response_content_disposition(self):
|
||||
@@ -405,6 +445,7 @@ class TestSwift3Object(Swift3FunctionalTestCase):
|
||||
status, headers, body = \
|
||||
self.conn.make_request('GET', self.bucket, obj, query=query)
|
||||
self.assertEquals(status, 200)
|
||||
assert_common_response_headers(self, headers)
|
||||
self.assertEquals(headers['content-disposition'], 'inline')
|
||||
|
||||
def test_get_object_response_content_encoding(self):
|
||||
@@ -415,6 +456,7 @@ class TestSwift3Object(Swift3FunctionalTestCase):
|
||||
status, headers, body = \
|
||||
self.conn.make_request('GET', self.bucket, obj, query=query)
|
||||
self.assertEquals(status, 200)
|
||||
assert_common_response_headers(self, headers)
|
||||
self.assertEquals(headers['content-encoding'], 'gzip')
|
||||
|
||||
def test_get_object_range(self):
|
||||
@@ -426,6 +468,7 @@ class TestSwift3Object(Swift3FunctionalTestCase):
|
||||
status, headers, body = \
|
||||
self.conn.make_request('GET', self.bucket, obj, headers=headers)
|
||||
self.assertEquals(status, 206)
|
||||
assert_common_response_headers(self, headers)
|
||||
self.assertEquals(headers['content-length'], '5')
|
||||
self.assertEquals(body, 'bcdef')
|
||||
|
||||
@@ -433,6 +476,7 @@ class TestSwift3Object(Swift3FunctionalTestCase):
|
||||
status, headers, body = \
|
||||
self.conn.make_request('GET', self.bucket, obj, headers=headers)
|
||||
self.assertEquals(status, 206)
|
||||
assert_common_response_headers(self, headers)
|
||||
self.assertEquals(headers['content-length'], '5')
|
||||
self.assertEquals(body, 'fghij')
|
||||
|
||||
@@ -440,6 +484,7 @@ class TestSwift3Object(Swift3FunctionalTestCase):
|
||||
status, headers, body = \
|
||||
self.conn.make_request('GET', self.bucket, obj, headers=headers)
|
||||
self.assertEquals(status, 206)
|
||||
assert_common_response_headers(self, headers)
|
||||
self.assertEquals(headers['content-length'], '5')
|
||||
self.assertEquals(body, 'fghij')
|
||||
|
||||
@@ -449,6 +494,7 @@ class TestSwift3Object(Swift3FunctionalTestCase):
|
||||
status, headers, body = \
|
||||
self.conn.make_request('GET', self.bucket, obj, headers=headers)
|
||||
self.assertEquals(status, 206)
|
||||
assert_common_response_headers(self, headers)
|
||||
|
||||
self.assertTrue('content-type' in headers) # sanity
|
||||
content_type, boundary = headers['content-type'].split(';')
|
||||
@@ -502,6 +548,7 @@ class TestSwift3Object(Swift3FunctionalTestCase):
|
||||
status, headers, body = \
|
||||
self.conn.make_request('GET', self.bucket, obj, headers=headers)
|
||||
self.assertEquals(status, 200)
|
||||
assert_common_response_headers(self, headers)
|
||||
|
||||
def test_get_object_if_unmodified_since(self):
|
||||
obj = 'object'
|
||||
@@ -515,6 +562,7 @@ class TestSwift3Object(Swift3FunctionalTestCase):
|
||||
status, headers, body = \
|
||||
self.conn.make_request('GET', self.bucket, obj, headers=headers)
|
||||
self.assertEquals(status, 200)
|
||||
assert_common_response_headers(self, headers)
|
||||
|
||||
def test_get_object_if_match(self):
|
||||
obj = 'object'
|
||||
@@ -528,6 +576,7 @@ class TestSwift3Object(Swift3FunctionalTestCase):
|
||||
status, headers, body = \
|
||||
self.conn.make_request('GET', self.bucket, obj, headers=headers)
|
||||
self.assertEquals(status, 200)
|
||||
assert_common_response_headers(self, headers)
|
||||
|
||||
def test_get_object_if_none_match(self):
|
||||
obj = 'object'
|
||||
@@ -537,6 +586,7 @@ class TestSwift3Object(Swift3FunctionalTestCase):
|
||||
status, headers, body = \
|
||||
self.conn.make_request('GET', self.bucket, obj, headers=headers)
|
||||
self.assertEquals(status, 200)
|
||||
assert_common_response_headers(self, headers)
|
||||
|
||||
def test_head_object_range(self):
|
||||
obj = 'object'
|
||||
@@ -547,16 +597,19 @@ class TestSwift3Object(Swift3FunctionalTestCase):
|
||||
status, headers, body = \
|
||||
self.conn.make_request('HEAD', self.bucket, obj, headers=headers)
|
||||
self.assertEquals(headers['content-length'], '5')
|
||||
assert_common_response_headers(self, headers)
|
||||
|
||||
headers = {'Range': 'bytes=5-'}
|
||||
status, headers, body = \
|
||||
self.conn.make_request('HEAD', self.bucket, obj, headers=headers)
|
||||
self.assertEquals(headers['content-length'], '5')
|
||||
assert_common_response_headers(self, headers)
|
||||
|
||||
headers = {'Range': 'bytes=-5'}
|
||||
status, headers, body = \
|
||||
self.conn.make_request('HEAD', self.bucket, obj, headers=headers)
|
||||
self.assertEquals(headers['content-length'], '5')
|
||||
assert_common_response_headers(self, headers)
|
||||
|
||||
def test_head_object_if_modified_since(self):
|
||||
obj = 'object'
|
||||
@@ -570,6 +623,7 @@ class TestSwift3Object(Swift3FunctionalTestCase):
|
||||
status, headers, body = \
|
||||
self.conn.make_request('HEAD', self.bucket, obj, headers=headers)
|
||||
self.assertEquals(status, 200)
|
||||
assert_common_response_headers(self, headers)
|
||||
|
||||
def test_head_object_if_unmodified_since(self):
|
||||
obj = 'object'
|
||||
@@ -583,6 +637,7 @@ class TestSwift3Object(Swift3FunctionalTestCase):
|
||||
status, headers, body = \
|
||||
self.conn.make_request('HEAD', self.bucket, obj, headers=headers)
|
||||
self.assertEquals(status, 200)
|
||||
assert_common_response_headers(self, headers)
|
||||
|
||||
def test_head_object_if_match(self):
|
||||
obj = 'object'
|
||||
@@ -596,6 +651,7 @@ class TestSwift3Object(Swift3FunctionalTestCase):
|
||||
status, headers, body = \
|
||||
self.conn.make_request('HEAD', self.bucket, obj, headers=headers)
|
||||
self.assertEquals(status, 200)
|
||||
assert_common_response_headers(self, headers)
|
||||
|
||||
def test_head_object_if_none_match(self):
|
||||
obj = 'object'
|
||||
@@ -605,6 +661,7 @@ class TestSwift3Object(Swift3FunctionalTestCase):
|
||||
status, headers, body = \
|
||||
self.conn.make_request('HEAD', self.bucket, obj, headers=headers)
|
||||
self.assertEquals(status, 200)
|
||||
assert_common_response_headers(self, headers)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
@@ -17,12 +17,21 @@ from hashlib import md5
|
||||
from swift3.etree import fromstring
|
||||
|
||||
|
||||
def assert_common_response_headers(self, headers):
|
||||
def assert_common_response_headers(self, headers, etag=None):
|
||||
"""
|
||||
asserting common response headers with args
|
||||
:param headers: a dict of response headers
|
||||
:param etag: a string of md5(content).hexdigest() if not given,
|
||||
this won't assert anything about etag. (e.g. DELETE obj)
|
||||
"""
|
||||
self.assertTrue(headers['x-amz-id-2'] is not None)
|
||||
self.assertTrue(headers['x-amz-request-id'] is not None)
|
||||
self.assertTrue(headers['date'] is not None)
|
||||
# TODO; requires consideration
|
||||
# self.assertTrue(headers['server'] is not None)
|
||||
if etag is not None:
|
||||
self.assertTrue('etag' in headers) # sanity
|
||||
self.assertEquals(etag, headers['etag'].strip('"'))
|
||||
|
||||
|
||||
def get_error_code(body):
|
||||
|
||||
Reference in New Issue
Block a user