def test_versioning_put(self): # Versioning not configured status, headers, body = self.conn.make_request('GET', 'bucket', query='versioning') self.assertEqual(status, 200) elem = fromstring(body) self.assertEqual(list(elem), []) # Enable versioning elem = Element('VersioningConfiguration') SubElement(elem, 'Status').text = 'Enabled' xml = tostring(elem) status, headers, body = self.conn.make_request('PUT', 'bucket', body=xml, query='versioning') self.assertEqual(status, 200) status, headers, body = self.conn.make_request('GET', 'bucket', query='versioning') self.assertEqual(status, 200) elem = fromstring(body) self.assertEqual(elem.find('./Status').text, 'Enabled') # Suspend versioning elem = Element('VersioningConfiguration') SubElement(elem, 'Status').text = 'Suspended' xml = tostring(elem) status, headers, body = self.conn.make_request('PUT', 'bucket', body=xml, query='versioning') self.assertEqual(status, 200) status, headers, body = self.conn.make_request('GET', 'bucket', query='versioning') self.assertEqual(status, 200) elem = fromstring(body) self.assertEqual(elem.find('./Status').text, 'Suspended') # Resume versioning elem = Element('VersioningConfiguration') SubElement(elem, 'Status').text = 'Enabled' xml = tostring(elem) status, headers, body = self.conn.make_request('PUT', 'bucket', body=xml, query='versioning') self.assertEqual(status, 200) status, headers, body = self.conn.make_request('GET', 'bucket', query='versioning') self.assertEqual(status, 200) elem = fromstring(body) self.assertEqual(elem.find('./Status').text, 'Enabled')
def test_object_multi_upload_part_copy_version(self): if 'object_versioning' not in tf.cluster_info: self.skipTest('Object Versioning not enabled') bucket = 'bucket' keys = ['obj1'] uploads = [] results_generator = self._initiate_multi_uploads_result_generator( bucket, keys) # Initiate Multipart Upload for expected_key, (status, headers, body) in \ zip(keys, results_generator): self.assertEqual(status, 200) self.assertCommonResponseHeaders(headers) self.assertTrue('content-type' in headers) self.assertEqual(headers['content-type'], 'application/xml') self.assertTrue('content-length' in headers) self.assertEqual(headers['content-length'], str(len(body))) elem = fromstring(body, 'InitiateMultipartUploadResult') self.assertEqual(elem.find('Bucket').text, bucket) key = elem.find('Key').text self.assertEqual(expected_key, key) upload_id = elem.find('UploadId').text self.assertTrue(upload_id is not None) self.assertTrue((key, upload_id) not in uploads) uploads.append((key, upload_id)) self.assertEqual(len(uploads), len(keys)) # sanity key, upload_id = uploads[0] src_bucket = 'bucket2' src_obj = 'obj4' src_content = b'y' * (self.min_segment_size // 2) + b'z' * \ self.min_segment_size etags = [md5(src_content, usedforsecurity=False).hexdigest()] # prepare null-version src obj self.conn.make_request('PUT', src_bucket) self.conn.make_request('PUT', src_bucket, src_obj, body=src_content) _, headers, _ = self.conn.make_request('HEAD', src_bucket, src_obj) self.assertCommonResponseHeaders(headers) # Turn on versioning elem = Element('VersioningConfiguration') SubElement(elem, 'Status').text = 'Enabled' xml = tostring(elem) status, headers, body = self.conn.make_request('PUT', src_bucket, body=xml, query='versioning') self.assertEqual(status, 200) src_obj2 = 'obj5' src_content2 = b'stub' etags.append(md5(src_content2, usedforsecurity=False).hexdigest()) # prepare src obj w/ real version self.conn.make_request('PUT', src_bucket, src_obj2, body=src_content2) _, headers, _ = self.conn.make_request('HEAD', src_bucket, src_obj2) self.assertCommonResponseHeaders(headers) version_id2 = headers['x-amz-version-id'] status, headers, body, resp_etag = \ self._upload_part_copy(src_bucket, src_obj, bucket, key, upload_id, 1, src_version_id='null') self.assertEqual(status, 200) self.assertCommonResponseHeaders(headers) self.assertTrue('content-type' in headers) self.assertEqual(headers['content-type'], 'application/xml') self.assertTrue('content-length' in headers) self.assertEqual(headers['content-length'], str(len(body))) self.assertTrue('etag' not in headers) elem = fromstring(body, 'CopyPartResult') last_modifieds = [elem.find('LastModified').text] self.assertTrue(last_modifieds[0] is not None) self.assertEqual(resp_etag, etags[0]) status, headers, body, resp_etag = \ self._upload_part_copy(src_bucket, src_obj2, bucket, key, upload_id, 2, src_version_id=version_id2) self.assertEqual(status, 200) self.assertCommonResponseHeaders(headers) self.assertTrue('content-type' in headers) self.assertEqual(headers['content-type'], 'application/xml') self.assertTrue('content-length' in headers) self.assertEqual(headers['content-length'], str(len(body))) self.assertTrue('etag' not in headers) elem = fromstring(body, 'CopyPartResult') last_modifieds.append(elem.find('LastModified').text) self.assertTrue(last_modifieds[1] is not None) self.assertEqual(resp_etag, etags[1]) # Check last-modified timestamp key, upload_id = uploads[0] query = 'uploadId=%s' % upload_id status, headers, body = \ self.conn.make_request('GET', bucket, key, query=query) elem = fromstring(body, 'ListPartsResult') # FIXME: COPY result drops milli/microseconds but GET doesn't last_modified_gets = [ p.find('LastModified').text for p in elem.iterfind('Part') ] self.assertEqual([lm.rsplit('.', 1)[0] for lm in last_modified_gets], [lm.rsplit('.', 1)[0] for lm in last_modifieds]) # There should be *exactly* two parts in the result self.assertEqual(2, len(last_modified_gets)) # Abort Multipart Upload key, upload_id = uploads[0] query = 'uploadId=%s' % upload_id status, headers, body = \ self.conn.make_request('DELETE', bucket, key, query=query) # sanity checks self.assertEqual(status, 204) self.assertCommonResponseHeaders(headers) self.assertTrue('content-type' in headers) self.assertEqual(headers['content-type'], 'text/html; charset=UTF-8') self.assertTrue('content-length' in headers) self.assertEqual(headers['content-length'], '0')