py3: symlink follow-up
- Have the unit tests use WSGI strings, like a real system. - Port the func tests. Change-Id: I3a6f409208de45ebf9f55f7f59e4fe6ac6fbe163
This commit is contained in:
parent
4f9595f113
commit
2e35376c6d
@ -199,12 +199,7 @@ def _check_symlink_header(req):
|
|||||||
# validation first, here.
|
# validation first, here.
|
||||||
error_body = 'X-Symlink-Target header must be of the form ' \
|
error_body = 'X-Symlink-Target header must be of the form ' \
|
||||||
'<container name>/<object name>'
|
'<container name>/<object name>'
|
||||||
try:
|
if wsgi_unquote(req.headers[TGT_OBJ_SYMLINK_HDR]).startswith('/'):
|
||||||
if wsgi_unquote(req.headers[TGT_OBJ_SYMLINK_HDR]).startswith('/'):
|
|
||||||
raise HTTPPreconditionFailed(
|
|
||||||
body=error_body,
|
|
||||||
request=req, content_type='text/plain')
|
|
||||||
except TypeError:
|
|
||||||
raise HTTPPreconditionFailed(
|
raise HTTPPreconditionFailed(
|
||||||
body=error_body,
|
body=error_body,
|
||||||
request=req, content_type='text/plain')
|
request=req, content_type='text/plain')
|
||||||
@ -216,14 +211,9 @@ def _check_symlink_header(req):
|
|||||||
req.headers[TGT_OBJ_SYMLINK_HDR] = wsgi_quote('%s/%s' % (container, obj))
|
req.headers[TGT_OBJ_SYMLINK_HDR] = wsgi_quote('%s/%s' % (container, obj))
|
||||||
|
|
||||||
# Check account format if it exists
|
# Check account format if it exists
|
||||||
try:
|
account = check_account_format(
|
||||||
account = check_account_format(
|
req, wsgi_unquote(req.headers[TGT_ACCT_SYMLINK_HDR])) \
|
||||||
req, wsgi_unquote(req.headers[TGT_ACCT_SYMLINK_HDR])) \
|
if TGT_ACCT_SYMLINK_HDR in req.headers else None
|
||||||
if TGT_ACCT_SYMLINK_HDR in req.headers else None
|
|
||||||
except TypeError:
|
|
||||||
raise HTTPPreconditionFailed(
|
|
||||||
body='Account name cannot contain slashes',
|
|
||||||
request=req, content_type='text/plain')
|
|
||||||
|
|
||||||
# Extract request path
|
# Extract request path
|
||||||
_junk, req_acc, req_cont, req_obj = req.split_path(4, 4, True)
|
_junk, req_acc, req_cont, req_obj = req.split_path(4, 4, True)
|
||||||
|
@ -40,42 +40,40 @@ class TestDloEnv(BaseEnv):
|
|||||||
if not cont.create():
|
if not cont.create():
|
||||||
raise ResponseError(cls.conn.response)
|
raise ResponseError(cls.conn.response)
|
||||||
|
|
||||||
# avoid getting a prefix that stops halfway through an encoded
|
prefix = Utils.create_name(10)
|
||||||
# character
|
|
||||||
prefix = Utils.create_name().decode("utf-8")[:10].encode("utf-8")
|
|
||||||
cls.segment_prefix = prefix
|
cls.segment_prefix = prefix
|
||||||
|
|
||||||
for letter in ('a', 'b', 'c', 'd', 'e'):
|
for letter in ('a', 'b', 'c', 'd', 'e'):
|
||||||
file_item = cls.container.file("%s/seg_lower%s" % (prefix, letter))
|
file_item = cls.container.file("%s/seg_lower%s" % (prefix, letter))
|
||||||
file_item.write(letter * 10)
|
file_item.write(letter.encode('ascii') * 10)
|
||||||
|
|
||||||
file_item = cls.container.file(
|
file_item = cls.container.file(
|
||||||
"%s/seg_upper_%%ff%s" % (prefix, letter))
|
"%s/seg_upper_%%ff%s" % (prefix, letter))
|
||||||
file_item.write(letter.upper() * 10)
|
file_item.write(letter.upper().encode('ascii') * 10)
|
||||||
|
|
||||||
for letter in ('f', 'g', 'h', 'i', 'j'):
|
for letter in ('f', 'g', 'h', 'i', 'j'):
|
||||||
file_item = cls.container2.file("%s/seg_lower%s" %
|
file_item = cls.container2.file("%s/seg_lower%s" %
|
||||||
(prefix, letter))
|
(prefix, letter))
|
||||||
file_item.write(letter * 10)
|
file_item.write(letter.encode('ascii') * 10)
|
||||||
|
|
||||||
man1 = cls.container.file("man1")
|
man1 = cls.container.file("man1")
|
||||||
man1.write('man1-contents',
|
man1.write(b'man1-contents',
|
||||||
hdrs={"X-Object-Manifest": "%s/%s/seg_lower" %
|
hdrs={"X-Object-Manifest": "%s/%s/seg_lower" %
|
||||||
(cls.container.name, prefix)})
|
(cls.container.name, prefix)})
|
||||||
|
|
||||||
man2 = cls.container.file("man2")
|
man2 = cls.container.file("man2")
|
||||||
man2.write('man2-contents',
|
man2.write(b'man2-contents',
|
||||||
hdrs={"X-Object-Manifest": "%s/%s/seg_upper_%%25ff" %
|
hdrs={"X-Object-Manifest": "%s/%s/seg_upper_%%25ff" %
|
||||||
(cls.container.name, prefix)})
|
(cls.container.name, prefix)})
|
||||||
|
|
||||||
manall = cls.container.file("manall")
|
manall = cls.container.file("manall")
|
||||||
manall.write('manall-contents',
|
manall.write(b'manall-contents',
|
||||||
hdrs={"X-Object-Manifest": "%s/%s/seg" %
|
hdrs={"X-Object-Manifest": "%s/%s/seg" %
|
||||||
(cls.container.name, prefix)})
|
(cls.container.name, prefix)})
|
||||||
|
|
||||||
mancont2 = cls.container.file("mancont2")
|
mancont2 = cls.container.file("mancont2")
|
||||||
mancont2.write(
|
mancont2.write(
|
||||||
'mancont2-contents',
|
b'mancont2-contents',
|
||||||
hdrs={"X-Object-Manifest": "%s/%s/seg_lower" %
|
hdrs={"X-Object-Manifest": "%s/%s/seg_lower" %
|
||||||
(cls.container2.name, prefix)})
|
(cls.container2.name, prefix)})
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ class TestSloEnv(BaseEnv):
|
|||||||
('e', 1)):
|
('e', 1)):
|
||||||
seg_name = "seg_%s" % letter
|
seg_name = "seg_%s" % letter
|
||||||
file_item = container.file(seg_name)
|
file_item = container.file(seg_name)
|
||||||
file_item.write(letter * size)
|
file_item.write(letter.encode('ascii') * size)
|
||||||
seg_info[seg_name] = {
|
seg_info[seg_name] = {
|
||||||
'size_bytes': size,
|
'size_bytes': size,
|
||||||
'etag': file_item.md5,
|
'etag': file_item.md5,
|
||||||
@ -93,24 +93,26 @@ class TestSloEnv(BaseEnv):
|
|||||||
file_item.write(
|
file_item.write(
|
||||||
json.dumps([seg_info['seg_a'], seg_info['seg_b'],
|
json.dumps([seg_info['seg_a'], seg_info['seg_b'],
|
||||||
seg_info['seg_c'], seg_info['seg_d'],
|
seg_info['seg_c'], seg_info['seg_d'],
|
||||||
seg_info['seg_e']]),
|
seg_info['seg_e']]).encode('ascii'),
|
||||||
parms={'multipart-manifest': 'put'})
|
parms={'multipart-manifest': 'put'})
|
||||||
|
|
||||||
cls.container.file('seg_with_%ff_funky_name').write('z' * 10)
|
cls.container.file('seg_with_%ff_funky_name').write(b'z' * 10)
|
||||||
|
|
||||||
# Put the same manifest in the container2
|
# Put the same manifest in the container2
|
||||||
file_item = cls.container2.file("manifest-abcde")
|
file_item = cls.container2.file("manifest-abcde")
|
||||||
file_item.write(
|
file_item.write(
|
||||||
json.dumps([seg_info['seg_a'], seg_info['seg_b'],
|
json.dumps([seg_info['seg_a'], seg_info['seg_b'],
|
||||||
seg_info['seg_c'], seg_info['seg_d'],
|
seg_info['seg_c'], seg_info['seg_d'],
|
||||||
seg_info['seg_e']]),
|
seg_info['seg_e']]).encode('ascii'),
|
||||||
parms={'multipart-manifest': 'put'})
|
parms={'multipart-manifest': 'put'})
|
||||||
|
|
||||||
file_item = cls.container.file('manifest-cd')
|
file_item = cls.container.file('manifest-cd')
|
||||||
cd_json = json.dumps([seg_info['seg_c'], seg_info['seg_d']])
|
cd_json = json.dumps([
|
||||||
|
seg_info['seg_c'], seg_info['seg_d']]).encode('ascii')
|
||||||
file_item.write(cd_json, parms={'multipart-manifest': 'put'})
|
file_item.write(cd_json, parms={'multipart-manifest': 'put'})
|
||||||
cd_etag = hashlib.md5(seg_info['seg_c']['etag'] +
|
cd_etag = hashlib.md5((
|
||||||
seg_info['seg_d']['etag']).hexdigest()
|
seg_info['seg_c']['etag'] + seg_info['seg_d']['etag']
|
||||||
|
).encode('ascii')).hexdigest()
|
||||||
|
|
||||||
file_item = cls.container.file("manifest-bcd-submanifest")
|
file_item = cls.container.file("manifest-bcd-submanifest")
|
||||||
file_item.write(
|
file_item.write(
|
||||||
@ -119,10 +121,10 @@ class TestSloEnv(BaseEnv):
|
|||||||
'size_bytes': (seg_info['seg_c']['size_bytes'] +
|
'size_bytes': (seg_info['seg_c']['size_bytes'] +
|
||||||
seg_info['seg_d']['size_bytes']),
|
seg_info['seg_d']['size_bytes']),
|
||||||
'path': '/%s/%s' % (cls.container.name,
|
'path': '/%s/%s' % (cls.container.name,
|
||||||
'manifest-cd')}]),
|
'manifest-cd')}]).encode('ascii'),
|
||||||
parms={'multipart-manifest': 'put'})
|
parms={'multipart-manifest': 'put'})
|
||||||
bcd_submanifest_etag = hashlib.md5(
|
bcd_submanifest_etag = hashlib.md5((
|
||||||
seg_info['seg_b']['etag'] + cd_etag).hexdigest()
|
seg_info['seg_b']['etag'] + cd_etag).encode('ascii')).hexdigest()
|
||||||
|
|
||||||
file_item = cls.container.file("manifest-abcde-submanifest")
|
file_item = cls.container.file("manifest-abcde-submanifest")
|
||||||
file_item.write(
|
file_item.write(
|
||||||
@ -134,11 +136,11 @@ class TestSloEnv(BaseEnv):
|
|||||||
seg_info['seg_d']['size_bytes']),
|
seg_info['seg_d']['size_bytes']),
|
||||||
'path': '/%s/%s' % (cls.container.name,
|
'path': '/%s/%s' % (cls.container.name,
|
||||||
'manifest-bcd-submanifest')},
|
'manifest-bcd-submanifest')},
|
||||||
seg_info['seg_e']]),
|
seg_info['seg_e']]).encode('ascii'),
|
||||||
parms={'multipart-manifest': 'put'})
|
parms={'multipart-manifest': 'put'})
|
||||||
abcde_submanifest_etag = hashlib.md5(
|
abcde_submanifest_etag = hashlib.md5((
|
||||||
seg_info['seg_a']['etag'] + bcd_submanifest_etag +
|
seg_info['seg_a']['etag'] + bcd_submanifest_etag +
|
||||||
seg_info['seg_e']['etag']).hexdigest()
|
seg_info['seg_e']['etag']).encode('ascii')).hexdigest()
|
||||||
abcde_submanifest_size = (seg_info['seg_a']['size_bytes'] +
|
abcde_submanifest_size = (seg_info['seg_a']['size_bytes'] +
|
||||||
seg_info['seg_b']['size_bytes'] +
|
seg_info['seg_b']['size_bytes'] +
|
||||||
seg_info['seg_c']['size_bytes'] +
|
seg_info['seg_c']['size_bytes'] +
|
||||||
@ -162,12 +164,13 @@ class TestSloEnv(BaseEnv):
|
|||||||
'size_bytes': abcde_submanifest_size,
|
'size_bytes': abcde_submanifest_size,
|
||||||
'path': '/%s/%s' % (cls.container.name,
|
'path': '/%s/%s' % (cls.container.name,
|
||||||
'manifest-abcde-submanifest'),
|
'manifest-abcde-submanifest'),
|
||||||
'range': '3145727-3145728'}]), # 'cd'
|
'range': '3145727-3145728'}]).encode('ascii'), # 'cd'
|
||||||
parms={'multipart-manifest': 'put'})
|
parms={'multipart-manifest': 'put'})
|
||||||
ranged_manifest_etag = hashlib.md5(
|
ranged_manifest_etag = hashlib.md5((
|
||||||
abcde_submanifest_etag + ':3145727-4194304;' +
|
abcde_submanifest_etag + ':3145727-4194304;' +
|
||||||
abcde_submanifest_etag + ':524288-1572863;' +
|
abcde_submanifest_etag + ':524288-1572863;' +
|
||||||
abcde_submanifest_etag + ':3145727-3145728;').hexdigest()
|
abcde_submanifest_etag + ':3145727-3145728;'
|
||||||
|
).encode('ascii')).hexdigest()
|
||||||
ranged_manifest_size = 2 * 1024 * 1024 + 4
|
ranged_manifest_size = 2 * 1024 * 1024 + 4
|
||||||
|
|
||||||
file_item = cls.container.file("ranged-submanifest")
|
file_item = cls.container.file("ranged-submanifest")
|
||||||
@ -187,7 +190,7 @@ class TestSloEnv(BaseEnv):
|
|||||||
'size_bytes': ranged_manifest_size,
|
'size_bytes': ranged_manifest_size,
|
||||||
'path': '/%s/%s' % (cls.container.name,
|
'path': '/%s/%s' % (cls.container.name,
|
||||||
'ranged-manifest'),
|
'ranged-manifest'),
|
||||||
'range': '-3'}]),
|
'range': '-3'}]).encode('ascii'),
|
||||||
parms={'multipart-manifest': 'put'})
|
parms={'multipart-manifest': 'put'})
|
||||||
|
|
||||||
file_item = cls.container.file("manifest-db")
|
file_item = cls.container.file("manifest-db")
|
||||||
@ -197,7 +200,7 @@ class TestSloEnv(BaseEnv):
|
|||||||
'size_bytes': None},
|
'size_bytes': None},
|
||||||
{'path': seg_info['seg_b']['path'], 'etag': None,
|
{'path': seg_info['seg_b']['path'], 'etag': None,
|
||||||
'size_bytes': None},
|
'size_bytes': None},
|
||||||
]), parms={'multipart-manifest': 'put'})
|
]).encode('ascii'), parms={'multipart-manifest': 'put'})
|
||||||
|
|
||||||
file_item = cls.container.file("ranged-manifest-repeated-segment")
|
file_item = cls.container.file("ranged-manifest-repeated-segment")
|
||||||
file_item.write(
|
file_item.write(
|
||||||
@ -208,20 +211,20 @@ class TestSloEnv(BaseEnv):
|
|||||||
'size_bytes': None},
|
'size_bytes': None},
|
||||||
{'path': seg_info['seg_b']['path'], 'etag': None,
|
{'path': seg_info['seg_b']['path'], 'etag': None,
|
||||||
'size_bytes': None, 'range': '-1048578'},
|
'size_bytes': None, 'range': '-1048578'},
|
||||||
]), parms={'multipart-manifest': 'put'})
|
]).encode('ascii'), parms={'multipart-manifest': 'put'})
|
||||||
|
|
||||||
file_item = cls.container.file("mixed-object-data-manifest")
|
file_item = cls.container.file("mixed-object-data-manifest")
|
||||||
file_item.write(
|
file_item.write(
|
||||||
json.dumps([
|
json.dumps([
|
||||||
{'data': base64.b64encode('APRE' * 8)},
|
{'data': base64.b64encode(b'APRE' * 8).decode('ascii')},
|
||||||
{'path': seg_info['seg_a']['path']},
|
{'path': seg_info['seg_a']['path']},
|
||||||
{'data': base64.b64encode('APOS' * 16)},
|
{'data': base64.b64encode(b'APOS' * 16).decode('ascii')},
|
||||||
{'path': seg_info['seg_b']['path']},
|
{'path': seg_info['seg_b']['path']},
|
||||||
{'data': base64.b64encode('BPOS' * 32)},
|
{'data': base64.b64encode(b'BPOS' * 32).decode('ascii')},
|
||||||
{'data': base64.b64encode('CPRE' * 64)},
|
{'data': base64.b64encode(b'CPRE' * 64).decode('ascii')},
|
||||||
{'path': seg_info['seg_c']['path']},
|
{'path': seg_info['seg_c']['path']},
|
||||||
{'data': base64.b64encode('CPOS' * 8)},
|
{'data': base64.b64encode(b'CPOS' * 8).decode('ascii')},
|
||||||
]), parms={'multipart-manifest': 'put'}
|
]).encode('ascii'), parms={'multipart-manifest': 'put'}
|
||||||
)
|
)
|
||||||
|
|
||||||
file_item = cls.container.file("nested-data-manifest")
|
file_item = cls.container.file("nested-data-manifest")
|
||||||
@ -229,7 +232,7 @@ class TestSloEnv(BaseEnv):
|
|||||||
json.dumps([
|
json.dumps([
|
||||||
{'path': '%s/%s' % (cls.container.name,
|
{'path': '%s/%s' % (cls.container.name,
|
||||||
"mixed-object-data-manifest")}
|
"mixed-object-data-manifest")}
|
||||||
]), parms={'multipart-manifest': 'put'}
|
]).encode('ascii'), parms={'multipart-manifest': 'put'}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ import hmac
|
|||||||
import unittest2
|
import unittest2
|
||||||
import itertools
|
import itertools
|
||||||
import hashlib
|
import hashlib
|
||||||
|
import six
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from six.moves import urllib
|
from six.moves import urllib
|
||||||
@ -35,8 +36,9 @@ from test.functional.test_tempurl import TestContainerTempurlEnv, \
|
|||||||
TestTempurlEnv
|
TestTempurlEnv
|
||||||
from test.functional.swift_test_client import ResponseError
|
from test.functional.swift_test_client import ResponseError
|
||||||
import test.functional as tf
|
import test.functional as tf
|
||||||
|
from test.unit import group_by_byte
|
||||||
|
|
||||||
TARGET_BODY = 'target body'
|
TARGET_BODY = b'target body'
|
||||||
|
|
||||||
|
|
||||||
def setUpModule():
|
def setUpModule():
|
||||||
@ -76,7 +78,7 @@ class TestSymlinkEnv(BaseEnv):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _make_request(cls, url, token, parsed, conn, method,
|
def _make_request(cls, url, token, parsed, conn, method,
|
||||||
container, obj='', headers=None, body='',
|
container, obj='', headers=None, body=b'',
|
||||||
query_args=None):
|
query_args=None):
|
||||||
headers = headers or {}
|
headers = headers or {}
|
||||||
headers.update({'X-Auth-Token': token})
|
headers.update({'X-Auth-Token': token})
|
||||||
@ -179,7 +181,7 @@ class TestSymlink(Base):
|
|||||||
self.env.tearDown()
|
self.env.tearDown()
|
||||||
|
|
||||||
def _make_request(self, url, token, parsed, conn, method,
|
def _make_request(self, url, token, parsed, conn, method,
|
||||||
container, obj='', headers=None, body='',
|
container, obj='', headers=None, body=b'',
|
||||||
query_args=None, allow_redirects=True):
|
query_args=None, allow_redirects=True):
|
||||||
headers = headers or {}
|
headers = headers or {}
|
||||||
headers.update({'X-Auth-Token': token})
|
headers.update({'X-Auth-Token': token})
|
||||||
@ -195,7 +197,7 @@ class TestSymlink(Base):
|
|||||||
return resp
|
return resp
|
||||||
|
|
||||||
def _make_request_with_symlink_get(self, url, token, parsed, conn, method,
|
def _make_request_with_symlink_get(self, url, token, parsed, conn, method,
|
||||||
container, obj, headers=None, body=''):
|
container, obj, headers=None, body=b''):
|
||||||
resp = self._make_request(
|
resp = self._make_request(
|
||||||
url, token, parsed, conn, method, container, obj, headers, body,
|
url, token, parsed, conn, method, container, obj, headers, body,
|
||||||
query_args='symlink=get')
|
query_args='symlink=get')
|
||||||
@ -245,7 +247,7 @@ class TestSymlink(Base):
|
|||||||
self._make_request_with_symlink_get, method='GET',
|
self._make_request_with_symlink_get, method='GET',
|
||||||
container=link_cont, obj=link_obj, use_account=use_account)
|
container=link_cont, obj=link_obj, use_account=use_account)
|
||||||
self.assertEqual(resp.status, 200)
|
self.assertEqual(resp.status, 200)
|
||||||
self.assertEqual(resp.content, '')
|
self.assertEqual(resp.content, b'')
|
||||||
self.assertEqual(resp.getheader('content-length'), str(0))
|
self.assertEqual(resp.getheader('content-length'), str(0))
|
||||||
self.assertTrue(resp.getheader('x-symlink-target'))
|
self.assertTrue(resp.getheader('x-symlink-target'))
|
||||||
|
|
||||||
@ -333,7 +335,7 @@ class TestSymlink(Base):
|
|||||||
container=self.env.link_cont, obj=link_obj,
|
container=self.env.link_cont, obj=link_obj,
|
||||||
headers=headers)
|
headers=headers)
|
||||||
self.assertEqual(resp.status, 206)
|
self.assertEqual(resp.status, 206)
|
||||||
self.assertEqual(resp.content, 'body')
|
self.assertEqual(resp.content, b'body')
|
||||||
|
|
||||||
def test_create_symlink_before_target(self):
|
def test_create_symlink_before_target(self):
|
||||||
link_obj = uuid4().hex
|
link_obj = uuid4().hex
|
||||||
@ -431,7 +433,7 @@ class TestSymlink(Base):
|
|||||||
container=container,
|
container=container,
|
||||||
obj=too_many_chain_link)
|
obj=too_many_chain_link)
|
||||||
self.assertEqual(resp.status, 409)
|
self.assertEqual(resp.status, 409)
|
||||||
self.assertEqual(resp.content, '')
|
self.assertEqual(resp.content, b'')
|
||||||
|
|
||||||
# try to GET to target object via too_many_chain_link
|
# try to GET to target object via too_many_chain_link
|
||||||
resp = retry(self._make_request, method='GET',
|
resp = retry(self._make_request, method='GET',
|
||||||
@ -440,7 +442,7 @@ class TestSymlink(Base):
|
|||||||
self.assertEqual(resp.status, 409)
|
self.assertEqual(resp.status, 409)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
resp.content,
|
resp.content,
|
||||||
'Too many levels of symbolic links, maximum allowed is %d' %
|
b'Too many levels of symbolic links, maximum allowed is %d' %
|
||||||
symloop_max)
|
symloop_max)
|
||||||
|
|
||||||
# However, HEAD/GET to the (just) link is still ok
|
# However, HEAD/GET to the (just) link is still ok
|
||||||
@ -522,7 +524,7 @@ class TestSymlink(Base):
|
|||||||
|
|
||||||
resp = retry(self._make_request, method='PUT',
|
resp = retry(self._make_request, method='PUT',
|
||||||
container=container, obj=too_many_recursion_manifest,
|
container=container, obj=too_many_recursion_manifest,
|
||||||
body=manifest,
|
body=manifest.encode('ascii'),
|
||||||
query_args='multipart-manifest=put')
|
query_args='multipart-manifest=put')
|
||||||
self.assertEqual(resp.status, 201) # sanity
|
self.assertEqual(resp.status, 201) # sanity
|
||||||
|
|
||||||
@ -533,8 +535,8 @@ class TestSymlink(Base):
|
|||||||
# N.B. This error message is from slo middleware that uses default.
|
# N.B. This error message is from slo middleware that uses default.
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
resp.content,
|
resp.content,
|
||||||
'<html><h1>Conflict</h1><p>There was a conflict when trying to'
|
b'<html><h1>Conflict</h1><p>There was a conflict when trying to'
|
||||||
' complete your request.</p></html>')
|
b' complete your request.</p></html>')
|
||||||
|
|
||||||
def test_symlink_put_missing_target_container(self):
|
def test_symlink_put_missing_target_container(self):
|
||||||
link_obj = uuid4().hex
|
link_obj = uuid4().hex
|
||||||
@ -546,8 +548,8 @@ class TestSymlink(Base):
|
|||||||
headers=headers)
|
headers=headers)
|
||||||
self.assertEqual(resp.status, 412)
|
self.assertEqual(resp.status, 412)
|
||||||
self.assertEqual(resp.content,
|
self.assertEqual(resp.content,
|
||||||
'X-Symlink-Target header must be of the form'
|
b'X-Symlink-Target header must be of the form'
|
||||||
' <container name>/<object name>')
|
b' <container name>/<object name>')
|
||||||
|
|
||||||
def test_symlink_put_non_zero_length(self):
|
def test_symlink_put_non_zero_length(self):
|
||||||
link_obj = uuid4().hex
|
link_obj = uuid4().hex
|
||||||
@ -559,7 +561,7 @@ class TestSymlink(Base):
|
|||||||
|
|
||||||
self.assertEqual(resp.status, 400)
|
self.assertEqual(resp.status, 400)
|
||||||
self.assertEqual(resp.content,
|
self.assertEqual(resp.content,
|
||||||
'Symlink requests require a zero byte body')
|
b'Symlink requests require a zero byte body')
|
||||||
|
|
||||||
def test_symlink_target_itself(self):
|
def test_symlink_target_itself(self):
|
||||||
link_obj = uuid4().hex
|
link_obj = uuid4().hex
|
||||||
@ -569,7 +571,7 @@ class TestSymlink(Base):
|
|||||||
container=self.env.link_cont, obj=link_obj,
|
container=self.env.link_cont, obj=link_obj,
|
||||||
headers=headers)
|
headers=headers)
|
||||||
self.assertEqual(resp.status, 400)
|
self.assertEqual(resp.status, 400)
|
||||||
self.assertEqual(resp.content, 'Symlink cannot target itself')
|
self.assertEqual(resp.content, b'Symlink cannot target itself')
|
||||||
|
|
||||||
def test_symlink_target_each_other(self):
|
def test_symlink_target_each_other(self):
|
||||||
symloop_max = cluster_info['symlink']['symloop_max']
|
symloop_max = cluster_info['symlink']['symloop_max']
|
||||||
@ -599,7 +601,7 @@ class TestSymlink(Base):
|
|||||||
self.assertEqual(resp.status, 409)
|
self.assertEqual(resp.status, 409)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
resp.content,
|
resp.content,
|
||||||
'Too many levels of symbolic links, maximum allowed is %d' %
|
b'Too many levels of symbolic links, maximum allowed is %d' %
|
||||||
symloop_max)
|
symloop_max)
|
||||||
|
|
||||||
def test_symlink_put_copy_from(self):
|
def test_symlink_put_copy_from(self):
|
||||||
@ -828,7 +830,7 @@ class TestSymlink(Base):
|
|||||||
obj=self.env.tgt_obj, headers=headers, allow_redirects=False)
|
obj=self.env.tgt_obj, headers=headers, allow_redirects=False)
|
||||||
self.assertEqual(resp.status, 400)
|
self.assertEqual(resp.status, 400)
|
||||||
self.assertEqual(resp.content,
|
self.assertEqual(resp.content,
|
||||||
'A PUT request is required to set a symlink target')
|
b'A PUT request is required to set a symlink target')
|
||||||
|
|
||||||
def test_overwrite_symlink(self):
|
def test_overwrite_symlink(self):
|
||||||
link_obj = uuid4().hex
|
link_obj = uuid4().hex
|
||||||
@ -1010,41 +1012,39 @@ class TestSymlinkSlo(Base):
|
|||||||
self.file_symlink.write(hdrs={'X-Symlink-Target':
|
self.file_symlink.write(hdrs={'X-Symlink-Target':
|
||||||
'%s/%s' % (self.env.container.name,
|
'%s/%s' % (self.env.container.name,
|
||||||
'manifest-abcde')})
|
'manifest-abcde')})
|
||||||
file_contents = self.file_symlink.read()
|
self.assertEqual([
|
||||||
self.assertEqual(4 * 1024 * 1024 + 1, len(file_contents))
|
(b'a', 1024 * 1024),
|
||||||
self.assertEqual('a', file_contents[0])
|
(b'b', 1024 * 1024),
|
||||||
self.assertEqual('a', file_contents[1024 * 1024 - 1])
|
(b'c', 1024 * 1024),
|
||||||
self.assertEqual('b', file_contents[1024 * 1024])
|
(b'd', 1024 * 1024),
|
||||||
self.assertEqual('d', file_contents[-2])
|
(b'e', 1),
|
||||||
self.assertEqual('e', file_contents[-1])
|
], group_by_byte(self.file_symlink.read()))
|
||||||
|
|
||||||
def test_symlink_target_slo_nested_manifest(self):
|
def test_symlink_target_slo_nested_manifest(self):
|
||||||
self.file_symlink.write(hdrs={'X-Symlink-Target':
|
self.file_symlink.write(hdrs={'X-Symlink-Target':
|
||||||
'%s/%s' % (self.env.container.name,
|
'%s/%s' % (self.env.container.name,
|
||||||
'manifest-abcde-submanifest')})
|
'manifest-abcde-submanifest')})
|
||||||
file_contents = self.file_symlink.read()
|
self.assertEqual([
|
||||||
self.assertEqual(4 * 1024 * 1024 + 1, len(file_contents))
|
(b'a', 1024 * 1024),
|
||||||
self.assertEqual('a', file_contents[0])
|
(b'b', 1024 * 1024),
|
||||||
self.assertEqual('a', file_contents[1024 * 1024 - 1])
|
(b'c', 1024 * 1024),
|
||||||
self.assertEqual('b', file_contents[1024 * 1024])
|
(b'd', 1024 * 1024),
|
||||||
self.assertEqual('d', file_contents[-2])
|
(b'e', 1),
|
||||||
self.assertEqual('e', file_contents[-1])
|
], group_by_byte(self.file_symlink.read()))
|
||||||
|
|
||||||
def test_slo_get_ranged_manifest(self):
|
def test_slo_get_ranged_manifest(self):
|
||||||
self.file_symlink.write(hdrs={'X-Symlink-Target':
|
self.file_symlink.write(hdrs={'X-Symlink-Target':
|
||||||
'%s/%s' % (self.env.container.name,
|
'%s/%s' % (self.env.container.name,
|
||||||
'ranged-manifest')})
|
'ranged-manifest')})
|
||||||
grouped_file_contents = [
|
|
||||||
(char, sum(1 for _char in grp))
|
|
||||||
for char, grp in itertools.groupby(self.file_symlink.read())]
|
|
||||||
self.assertEqual([
|
self.assertEqual([
|
||||||
('c', 1),
|
(b'c', 1),
|
||||||
('d', 1024 * 1024),
|
(b'd', 1024 * 1024),
|
||||||
('e', 1),
|
(b'e', 1),
|
||||||
('a', 512 * 1024),
|
(b'a', 512 * 1024),
|
||||||
('b', 512 * 1024),
|
(b'b', 512 * 1024),
|
||||||
('c', 1),
|
(b'c', 1),
|
||||||
('d', 1)], grouped_file_contents)
|
(b'd', 1),
|
||||||
|
], group_by_byte(self.file_symlink.read()))
|
||||||
|
|
||||||
def test_slo_ranged_get(self):
|
def test_slo_ranged_get(self):
|
||||||
self.file_symlink.write(hdrs={'X-Symlink-Target':
|
self.file_symlink.write(hdrs={'X-Symlink-Target':
|
||||||
@ -1052,10 +1052,11 @@ class TestSymlinkSlo(Base):
|
|||||||
'manifest-abcde')})
|
'manifest-abcde')})
|
||||||
file_contents = self.file_symlink.read(size=1024 * 1024 + 2,
|
file_contents = self.file_symlink.read(size=1024 * 1024 + 2,
|
||||||
offset=1024 * 1024 - 1)
|
offset=1024 * 1024 - 1)
|
||||||
self.assertEqual('a', file_contents[0])
|
self.assertEqual([
|
||||||
self.assertEqual('b', file_contents[1])
|
(b'a', 1),
|
||||||
self.assertEqual('b', file_contents[-2])
|
(b'b', 1024 * 1024),
|
||||||
self.assertEqual('c', file_contents[-1])
|
(b'c', 1),
|
||||||
|
], group_by_byte(file_contents))
|
||||||
|
|
||||||
|
|
||||||
class TestSymlinkSloEnv(TestSloEnv):
|
class TestSymlinkSloEnv(TestSloEnv):
|
||||||
@ -1081,7 +1082,7 @@ class TestSymlinkSloEnv(TestSloEnv):
|
|||||||
file_item = cls.container.file("manifest-linkto-ab")
|
file_item = cls.container.file("manifest-linkto-ab")
|
||||||
file_item.write(
|
file_item.write(
|
||||||
json.dumps([cls.link_seg_info['linkto_seg_a'],
|
json.dumps([cls.link_seg_info['linkto_seg_a'],
|
||||||
cls.link_seg_info['linkto_seg_b']]),
|
cls.link_seg_info['linkto_seg_b']]).encode('ascii'),
|
||||||
parms={'multipart-manifest': 'put'})
|
parms={'multipart-manifest': 'put'})
|
||||||
|
|
||||||
|
|
||||||
@ -1106,18 +1107,18 @@ class TestSymlinkToSloSegments(Base):
|
|||||||
|
|
||||||
def test_slo_get_simple_manifest_with_links(self):
|
def test_slo_get_simple_manifest_with_links(self):
|
||||||
file_item = self.env.container.file("manifest-linkto-ab")
|
file_item = self.env.container.file("manifest-linkto-ab")
|
||||||
file_contents = file_item.read()
|
self.assertEqual([
|
||||||
self.assertEqual(2 * 1024 * 1024, len(file_contents))
|
(b'a', 1024 * 1024),
|
||||||
self.assertEqual('a', file_contents[0])
|
(b'b', 1024 * 1024),
|
||||||
self.assertEqual('a', file_contents[1024 * 1024 - 1])
|
], group_by_byte(file_item.read()))
|
||||||
self.assertEqual('b', file_contents[1024 * 1024])
|
|
||||||
|
|
||||||
def test_slo_container_listing(self):
|
def test_slo_container_listing(self):
|
||||||
# the listing object size should equal the sum of the size of the
|
# the listing object size should equal the sum of the size of the
|
||||||
# segments, not the size of the manifest body
|
# segments, not the size of the manifest body
|
||||||
file_item = self.env.container.file(Utils.create_name())
|
file_item = self.env.container.file(Utils.create_name())
|
||||||
file_item.write(
|
file_item.write(
|
||||||
json.dumps([self.env.link_seg_info['linkto_seg_a']]),
|
json.dumps([
|
||||||
|
self.env.link_seg_info['linkto_seg_a']]).encode('ascii'),
|
||||||
parms={'multipart-manifest': 'put'})
|
parms={'multipart-manifest': 'put'})
|
||||||
|
|
||||||
# The container listing has the etag of the actual manifest object
|
# The container listing has the etag of the actual manifest object
|
||||||
@ -1182,8 +1183,10 @@ class TestSymlinkToSloSegments(Base):
|
|||||||
|
|
||||||
def test_slo_etag_is_hash_of_etags(self):
|
def test_slo_etag_is_hash_of_etags(self):
|
||||||
expected_hash = hashlib.md5()
|
expected_hash = hashlib.md5()
|
||||||
expected_hash.update(hashlib.md5('a' * 1024 * 1024).hexdigest())
|
expected_hash.update(hashlib.md5(
|
||||||
expected_hash.update(hashlib.md5('b' * 1024 * 1024).hexdigest())
|
b'a' * 1024 * 1024).hexdigest().encode('ascii'))
|
||||||
|
expected_hash.update(hashlib.md5(
|
||||||
|
b'b' * 1024 * 1024).hexdigest().encode('ascii'))
|
||||||
expected_etag = expected_hash.hexdigest()
|
expected_etag = expected_hash.hexdigest()
|
||||||
|
|
||||||
file_item = self.env.container.file('manifest-linkto-ab')
|
file_item = self.env.container.file('manifest-linkto-ab')
|
||||||
@ -1194,8 +1197,10 @@ class TestSymlinkToSloSegments(Base):
|
|||||||
file_item.copy(self.env.container.name, "copied-abcde")
|
file_item.copy(self.env.container.name, "copied-abcde")
|
||||||
|
|
||||||
copied = self.env.container.file("copied-abcde")
|
copied = self.env.container.file("copied-abcde")
|
||||||
copied_contents = copied.read(parms={'multipart-manifest': 'get'})
|
self.assertEqual([
|
||||||
self.assertEqual(2 * 1024 * 1024, len(copied_contents))
|
(b'a', 1024 * 1024),
|
||||||
|
(b'b', 1024 * 1024),
|
||||||
|
], group_by_byte(copied.read(parms={'multipart-manifest': 'get'})))
|
||||||
|
|
||||||
def test_slo_copy_the_manifest(self):
|
def test_slo_copy_the_manifest(self):
|
||||||
# first just perform some tests of the contents of the manifest itself
|
# first just perform some tests of the contents of the manifest itself
|
||||||
@ -1270,31 +1275,44 @@ class TestSymlinkDlo(Base):
|
|||||||
'%s/%s' % (self.env.container.name,
|
'%s/%s' % (self.env.container.name,
|
||||||
'man1')})
|
'man1')})
|
||||||
|
|
||||||
file_contents = file_symlink.read()
|
self.assertEqual([
|
||||||
self.assertEqual(
|
(b'a', 10),
|
||||||
file_contents,
|
(b'b', 10),
|
||||||
"aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeee")
|
(b'c', 10),
|
||||||
|
(b'd', 10),
|
||||||
|
(b'e', 10),
|
||||||
|
], group_by_byte(file_symlink.read()))
|
||||||
|
|
||||||
link_obj = uuid4().hex
|
link_obj = uuid4().hex
|
||||||
file_symlink = self.env.container.file(link_obj)
|
file_symlink = self.env.container.file(link_obj)
|
||||||
file_symlink.write(hdrs={'X-Symlink-Target':
|
file_symlink.write(hdrs={'X-Symlink-Target':
|
||||||
'%s/%s' % (self.env.container.name,
|
'%s/%s' % (self.env.container.name,
|
||||||
'man2')})
|
'man2')})
|
||||||
file_contents = file_symlink.read()
|
self.assertEqual([
|
||||||
self.assertEqual(
|
(b'A', 10),
|
||||||
file_contents,
|
(b'B', 10),
|
||||||
"AAAAAAAAAABBBBBBBBBBCCCCCCCCCCDDDDDDDDDDEEEEEEEEEE")
|
(b'C', 10),
|
||||||
|
(b'D', 10),
|
||||||
|
(b'E', 10),
|
||||||
|
], group_by_byte(file_symlink.read()))
|
||||||
|
|
||||||
link_obj = uuid4().hex
|
link_obj = uuid4().hex
|
||||||
file_symlink = self.env.container.file(link_obj)
|
file_symlink = self.env.container.file(link_obj)
|
||||||
file_symlink.write(hdrs={'X-Symlink-Target':
|
file_symlink.write(hdrs={'X-Symlink-Target':
|
||||||
'%s/%s' % (self.env.container.name,
|
'%s/%s' % (self.env.container.name,
|
||||||
'manall')})
|
'manall')})
|
||||||
file_contents = file_symlink.read()
|
self.assertEqual([
|
||||||
self.assertEqual(
|
(b'a', 10),
|
||||||
file_contents,
|
(b'b', 10),
|
||||||
("aaaaaaaaaabbbbbbbbbbccccccccccddddddddddeeeeeeeeee" +
|
(b'c', 10),
|
||||||
"AAAAAAAAAABBBBBBBBBBCCCCCCCCCCDDDDDDDDDDEEEEEEEEEE"))
|
(b'd', 10),
|
||||||
|
(b'e', 10),
|
||||||
|
(b'A', 10),
|
||||||
|
(b'B', 10),
|
||||||
|
(b'C', 10),
|
||||||
|
(b'D', 10),
|
||||||
|
(b'E', 10),
|
||||||
|
], group_by_byte(file_symlink.read()))
|
||||||
|
|
||||||
def test_get_manifest_document_itself(self):
|
def test_get_manifest_document_itself(self):
|
||||||
link_obj = uuid4().hex
|
link_obj = uuid4().hex
|
||||||
@ -1303,7 +1321,7 @@ class TestSymlinkDlo(Base):
|
|||||||
'%s/%s' % (self.env.container.name,
|
'%s/%s' % (self.env.container.name,
|
||||||
'man1')})
|
'man1')})
|
||||||
file_contents = file_symlink.read(parms={'multipart-manifest': 'get'})
|
file_contents = file_symlink.read(parms={'multipart-manifest': 'get'})
|
||||||
self.assertEqual(file_contents, "man1-contents")
|
self.assertEqual(file_contents, b"man1-contents")
|
||||||
self.assertEqual(file_symlink.info()['x_object_manifest'],
|
self.assertEqual(file_symlink.info()['x_object_manifest'],
|
||||||
"%s/%s/seg_lower" %
|
"%s/%s/seg_lower" %
|
||||||
(self.env.container.name, self.env.segment_prefix))
|
(self.env.container.name, self.env.segment_prefix))
|
||||||
@ -1314,11 +1332,15 @@ class TestSymlinkDlo(Base):
|
|||||||
file_symlink.write(hdrs={'X-Symlink-Target':
|
file_symlink.write(hdrs={'X-Symlink-Target':
|
||||||
'%s/%s' % (self.env.container.name,
|
'%s/%s' % (self.env.container.name,
|
||||||
'man1')})
|
'man1')})
|
||||||
file_contents = file_symlink.read(size=25, offset=8)
|
self.assertEqual([
|
||||||
self.assertEqual(file_contents, "aabbbbbbbbbbccccccccccddd")
|
(b'a', 2),
|
||||||
|
(b'b', 10),
|
||||||
|
(b'c', 10),
|
||||||
|
(b'd', 3),
|
||||||
|
], group_by_byte(file_symlink.read(size=25, offset=8)))
|
||||||
|
|
||||||
file_contents = file_symlink.read(size=1, offset=47)
|
file_contents = file_symlink.read(size=1, offset=47)
|
||||||
self.assertEqual(file_contents, "e")
|
self.assertEqual(file_contents, b"e")
|
||||||
|
|
||||||
def test_get_range_out_of_range(self):
|
def test_get_range_out_of_range(self):
|
||||||
link_obj = uuid4().hex
|
link_obj = uuid4().hex
|
||||||
@ -1373,7 +1395,7 @@ class TestSymlinkTargetObjectComparison(Base):
|
|||||||
if self.env.expect_body:
|
if self.env.expect_body:
|
||||||
self.assertTrue(body)
|
self.assertTrue(body)
|
||||||
else:
|
else:
|
||||||
self.assertEqual('', body)
|
self.assertEqual(b'', body)
|
||||||
self.assert_status(200)
|
self.assert_status(200)
|
||||||
self.assert_header('etag', md5)
|
self.assert_header('etag', md5)
|
||||||
|
|
||||||
@ -1395,7 +1417,7 @@ class TestSymlinkTargetObjectComparison(Base):
|
|||||||
if self.env.expect_body:
|
if self.env.expect_body:
|
||||||
self.assertTrue(body)
|
self.assertTrue(body)
|
||||||
else:
|
else:
|
||||||
self.assertEqual('', body)
|
self.assertEqual(b'', body)
|
||||||
self.assert_status(200)
|
self.assert_status(200)
|
||||||
self.assert_header('etag', md5)
|
self.assert_header('etag', md5)
|
||||||
|
|
||||||
@ -1417,7 +1439,7 @@ class TestSymlinkTargetObjectComparison(Base):
|
|||||||
if self.env.expect_body:
|
if self.env.expect_body:
|
||||||
self.assertTrue(body)
|
self.assertTrue(body)
|
||||||
else:
|
else:
|
||||||
self.assertEqual('', body)
|
self.assertEqual(b'', body)
|
||||||
self.assert_status(200)
|
self.assert_status(200)
|
||||||
self.assert_header('etag', md5)
|
self.assert_header('etag', md5)
|
||||||
|
|
||||||
@ -1440,7 +1462,7 @@ class TestSymlinkTargetObjectComparison(Base):
|
|||||||
if self.env.expect_body:
|
if self.env.expect_body:
|
||||||
self.assertTrue(body)
|
self.assertTrue(body)
|
||||||
else:
|
else:
|
||||||
self.assertEqual('', body)
|
self.assertEqual(b'', body)
|
||||||
self.assert_status(200)
|
self.assert_status(200)
|
||||||
self.assert_header('etag', md5)
|
self.assert_header('etag', md5)
|
||||||
|
|
||||||
@ -1464,7 +1486,7 @@ class TestSymlinkTargetObjectComparison(Base):
|
|||||||
if self.env.expect_body:
|
if self.env.expect_body:
|
||||||
self.assertTrue(body)
|
self.assertTrue(body)
|
||||||
else:
|
else:
|
||||||
self.assertEqual('', body)
|
self.assertEqual(b'', body)
|
||||||
self.assert_status(200)
|
self.assert_status(200)
|
||||||
self.assert_header('etag', md5)
|
self.assert_header('etag', md5)
|
||||||
self.assertTrue(file_symlink.info(hdrs=hdrs, parms=self.env.parms))
|
self.assertTrue(file_symlink.info(hdrs=hdrs, parms=self.env.parms))
|
||||||
@ -1493,7 +1515,7 @@ class TestSymlinkTargetObjectComparison(Base):
|
|||||||
if self.env.expect_body:
|
if self.env.expect_body:
|
||||||
self.assertTrue(body)
|
self.assertTrue(body)
|
||||||
else:
|
else:
|
||||||
self.assertEqual('', body)
|
self.assertEqual(b'', body)
|
||||||
self.assert_status(200)
|
self.assert_status(200)
|
||||||
self.assert_header('etag', md5)
|
self.assert_header('etag', md5)
|
||||||
self.assertTrue(file_symlink.info(hdrs=hdrs, parms=self.env.parms))
|
self.assertTrue(file_symlink.info(hdrs=hdrs, parms=self.env.parms))
|
||||||
@ -1521,7 +1543,7 @@ class TestSymlinkTargetObjectComparison(Base):
|
|||||||
if self.env.expect_body:
|
if self.env.expect_body:
|
||||||
self.assertTrue(body)
|
self.assertTrue(body)
|
||||||
else:
|
else:
|
||||||
self.assertEqual('', body)
|
self.assertEqual(b'', body)
|
||||||
self.assert_status(200)
|
self.assert_status(200)
|
||||||
self.assert_header('etag', md5)
|
self.assert_header('etag', md5)
|
||||||
|
|
||||||
@ -1600,7 +1622,7 @@ class TestSymlinkComparison(TestSymlinkTargetObjectComparison):
|
|||||||
|
|
||||||
hdrs = {'If-Modified-Since': put_target_last_modified}
|
hdrs = {'If-Modified-Since': put_target_last_modified}
|
||||||
body = file_symlink.read(hdrs=hdrs, parms=self.env.parms)
|
body = file_symlink.read(hdrs=hdrs, parms=self.env.parms)
|
||||||
self.assertEqual('', body)
|
self.assertEqual(b'', body)
|
||||||
self.assert_status(200)
|
self.assert_status(200)
|
||||||
self.assert_header('etag', md5)
|
self.assert_header('etag', md5)
|
||||||
|
|
||||||
@ -1613,7 +1635,7 @@ class TestSymlinkComparison(TestSymlinkTargetObjectComparison):
|
|||||||
|
|
||||||
hdrs = {'If-Unmodified-Since': last_modified}
|
hdrs = {'If-Unmodified-Since': last_modified}
|
||||||
body = file_symlink.read(hdrs=hdrs, parms=self.env.parms)
|
body = file_symlink.read(hdrs=hdrs, parms=self.env.parms)
|
||||||
self.assertEqual('', body)
|
self.assertEqual(b'', body)
|
||||||
self.assert_status(200)
|
self.assert_status(200)
|
||||||
self.assert_header('etag', md5)
|
self.assert_header('etag', md5)
|
||||||
|
|
||||||
@ -1644,9 +1666,14 @@ class TestSymlinkAccountTempurl(Base):
|
|||||||
self.env.tempurl_key)
|
self.env.tempurl_key)
|
||||||
|
|
||||||
def tempurl_parms(self, method, expires, path, key):
|
def tempurl_parms(self, method, expires, path, key):
|
||||||
|
path = urllib.parse.unquote(path)
|
||||||
|
if not six.PY2:
|
||||||
|
method = method.encode('utf8')
|
||||||
|
path = path.encode('utf8')
|
||||||
|
key = key.encode('utf8')
|
||||||
sig = hmac.new(
|
sig = hmac.new(
|
||||||
key,
|
key,
|
||||||
'%s\n%s\n%s' % (method, expires, urllib.parse.unquote(path)),
|
b'%s\n%d\n%s' % (method, expires, path),
|
||||||
self.digest).hexdigest()
|
self.digest).hexdigest()
|
||||||
return {'temp_url_sig': sig, 'temp_url_expires': str(expires)}
|
return {'temp_url_sig': sig, 'temp_url_expires': str(expires)}
|
||||||
|
|
||||||
@ -1662,7 +1689,7 @@ class TestSymlinkAccountTempurl(Base):
|
|||||||
# try to create symlink object
|
# try to create symlink object
|
||||||
try:
|
try:
|
||||||
new_sym.write(
|
new_sym.write(
|
||||||
'', {'x-symlink-target': 'cont/foo'}, parms=put_parms,
|
b'', {'x-symlink-target': 'cont/foo'}, parms=put_parms,
|
||||||
cfg={'no_auth_token': True})
|
cfg={'no_auth_token': True})
|
||||||
except ResponseError as e:
|
except ResponseError as e:
|
||||||
self.assertEqual(e.status, 400)
|
self.assertEqual(e.status, 400)
|
||||||
@ -1672,9 +1699,9 @@ class TestSymlinkAccountTempurl(Base):
|
|||||||
def test_GET_symlink_inside_container(self):
|
def test_GET_symlink_inside_container(self):
|
||||||
tgt_obj = self.env.container.file(Utils.create_name())
|
tgt_obj = self.env.container.file(Utils.create_name())
|
||||||
sym = self.env.container.file(Utils.create_name())
|
sym = self.env.container.file(Utils.create_name())
|
||||||
tgt_obj.write("target object body")
|
tgt_obj.write(b"target object body")
|
||||||
sym.write(
|
sym.write(
|
||||||
'',
|
b'',
|
||||||
{'x-symlink-target': '%s/%s' % (self.env.container.name, tgt_obj)})
|
{'x-symlink-target': '%s/%s' % (self.env.container.name, tgt_obj)})
|
||||||
|
|
||||||
expires = int(time.time()) + 86400
|
expires = int(time.time()) + 86400
|
||||||
@ -1684,18 +1711,18 @@ class TestSymlinkAccountTempurl(Base):
|
|||||||
|
|
||||||
contents = sym.read(parms=get_parms, cfg={'no_auth_token': True})
|
contents = sym.read(parms=get_parms, cfg={'no_auth_token': True})
|
||||||
self.assert_status([200])
|
self.assert_status([200])
|
||||||
self.assertEqual(contents, "target object body")
|
self.assertEqual(contents, b"target object body")
|
||||||
|
|
||||||
def test_GET_symlink_outside_container(self):
|
def test_GET_symlink_outside_container(self):
|
||||||
tgt_obj = self.env.container.file(Utils.create_name())
|
tgt_obj = self.env.container.file(Utils.create_name())
|
||||||
tgt_obj.write("target object body")
|
tgt_obj.write(b"target object body")
|
||||||
|
|
||||||
container2 = self.env.account.container(Utils.create_name())
|
container2 = self.env.account.container(Utils.create_name())
|
||||||
container2.create()
|
container2.create()
|
||||||
|
|
||||||
sym = container2.file(Utils.create_name())
|
sym = container2.file(Utils.create_name())
|
||||||
sym.write(
|
sym.write(
|
||||||
'',
|
b'',
|
||||||
{'x-symlink-target': '%s/%s' % (self.env.container.name, tgt_obj)})
|
{'x-symlink-target': '%s/%s' % (self.env.container.name, tgt_obj)})
|
||||||
|
|
||||||
expires = int(time.time()) + 86400
|
expires = int(time.time()) + 86400
|
||||||
@ -1706,7 +1733,7 @@ class TestSymlinkAccountTempurl(Base):
|
|||||||
# cross container tempurl works fine for account tempurl key
|
# cross container tempurl works fine for account tempurl key
|
||||||
contents = sym.read(parms=get_parms, cfg={'no_auth_token': True})
|
contents = sym.read(parms=get_parms, cfg={'no_auth_token': True})
|
||||||
self.assert_status([200])
|
self.assert_status([200])
|
||||||
self.assertEqual(contents, "target object body")
|
self.assertEqual(contents, b"target object body")
|
||||||
|
|
||||||
|
|
||||||
class TestSymlinkContainerTempurl(Base):
|
class TestSymlinkContainerTempurl(Base):
|
||||||
@ -1737,9 +1764,14 @@ class TestSymlinkContainerTempurl(Base):
|
|||||||
'temp_url_expires': str(expires)}
|
'temp_url_expires': str(expires)}
|
||||||
|
|
||||||
def tempurl_sig(self, method, expires, path, key):
|
def tempurl_sig(self, method, expires, path, key):
|
||||||
|
path = urllib.parse.unquote(path)
|
||||||
|
if not six.PY2:
|
||||||
|
method = method.encode('utf8')
|
||||||
|
path = path.encode('utf8')
|
||||||
|
key = key.encode('utf8')
|
||||||
return hmac.new(
|
return hmac.new(
|
||||||
key,
|
key,
|
||||||
'%s\n%s\n%s' % (method, expires, urllib.parse.unquote(path)),
|
b'%s\n%d\n%s' % (method, expires, path),
|
||||||
self.digest).hexdigest()
|
self.digest).hexdigest()
|
||||||
|
|
||||||
def test_PUT_symlink(self):
|
def test_PUT_symlink(self):
|
||||||
@ -1756,7 +1788,7 @@ class TestSymlinkContainerTempurl(Base):
|
|||||||
# try to create symlink object, should fail
|
# try to create symlink object, should fail
|
||||||
try:
|
try:
|
||||||
new_sym.write(
|
new_sym.write(
|
||||||
'', {'x-symlink-target': 'cont/foo'}, parms=put_parms,
|
b'', {'x-symlink-target': 'cont/foo'}, parms=put_parms,
|
||||||
cfg={'no_auth_token': True})
|
cfg={'no_auth_token': True})
|
||||||
except ResponseError as e:
|
except ResponseError as e:
|
||||||
self.assertEqual(e.status, 400)
|
self.assertEqual(e.status, 400)
|
||||||
@ -1766,9 +1798,9 @@ class TestSymlinkContainerTempurl(Base):
|
|||||||
def test_GET_symlink_inside_container(self):
|
def test_GET_symlink_inside_container(self):
|
||||||
tgt_obj = self.env.container.file(Utils.create_name())
|
tgt_obj = self.env.container.file(Utils.create_name())
|
||||||
sym = self.env.container.file(Utils.create_name())
|
sym = self.env.container.file(Utils.create_name())
|
||||||
tgt_obj.write("target object body")
|
tgt_obj.write(b"target object body")
|
||||||
sym.write(
|
sym.write(
|
||||||
'',
|
b'',
|
||||||
{'x-symlink-target': '%s/%s' % (self.env.container.name, tgt_obj)})
|
{'x-symlink-target': '%s/%s' % (self.env.container.name, tgt_obj)})
|
||||||
|
|
||||||
expires = int(time.time()) + 86400
|
expires = int(time.time()) + 86400
|
||||||
@ -1780,18 +1812,18 @@ class TestSymlinkContainerTempurl(Base):
|
|||||||
|
|
||||||
contents = sym.read(parms=parms, cfg={'no_auth_token': True})
|
contents = sym.read(parms=parms, cfg={'no_auth_token': True})
|
||||||
self.assert_status([200])
|
self.assert_status([200])
|
||||||
self.assertEqual(contents, "target object body")
|
self.assertEqual(contents, b"target object body")
|
||||||
|
|
||||||
def test_GET_symlink_outside_container(self):
|
def test_GET_symlink_outside_container(self):
|
||||||
tgt_obj = self.env.container.file(Utils.create_name())
|
tgt_obj = self.env.container.file(Utils.create_name())
|
||||||
tgt_obj.write("target object body")
|
tgt_obj.write(b"target object body")
|
||||||
|
|
||||||
container2 = self.env.account.container(Utils.create_name())
|
container2 = self.env.account.container(Utils.create_name())
|
||||||
container2.create()
|
container2.create()
|
||||||
|
|
||||||
sym = container2.file(Utils.create_name())
|
sym = container2.file(Utils.create_name())
|
||||||
sym.write(
|
sym.write(
|
||||||
'',
|
b'',
|
||||||
{'x-symlink-target': '%s/%s' % (self.env.container.name, tgt_obj)})
|
{'x-symlink-target': '%s/%s' % (self.env.container.name, tgt_obj)})
|
||||||
|
|
||||||
expires = int(time.time()) + 86400
|
expires = int(time.time()) + 86400
|
||||||
|
@ -82,9 +82,9 @@ class TestTempurlEnv(TestTempurlBaseEnv):
|
|||||||
raise ResponseError(cls.conn.response)
|
raise ResponseError(cls.conn.response)
|
||||||
|
|
||||||
cls.obj = cls.container.file(Utils.create_name())
|
cls.obj = cls.container.file(Utils.create_name())
|
||||||
cls.obj.write("obj contents")
|
cls.obj.write(b"obj contents")
|
||||||
cls.other_obj = cls.container.file(Utils.create_name())
|
cls.other_obj = cls.container.file(Utils.create_name())
|
||||||
cls.other_obj.write("other obj contents")
|
cls.other_obj.write(b"other obj contents")
|
||||||
|
|
||||||
|
|
||||||
class TestTempurl(Base):
|
class TestTempurl(Base):
|
||||||
@ -437,9 +437,9 @@ class TestContainerTempurlEnv(BaseEnv):
|
|||||||
raise ResponseError(cls.conn.response)
|
raise ResponseError(cls.conn.response)
|
||||||
|
|
||||||
cls.obj = cls.container.file(Utils.create_name())
|
cls.obj = cls.container.file(Utils.create_name())
|
||||||
cls.obj.write("obj contents")
|
cls.obj.write(b"obj contents")
|
||||||
cls.other_obj = cls.container.file(Utils.create_name())
|
cls.other_obj = cls.container.file(Utils.create_name())
|
||||||
cls.other_obj.write("other obj contents")
|
cls.other_obj.write(b"other obj contents")
|
||||||
|
|
||||||
|
|
||||||
class TestContainerTempurl(Base):
|
class TestContainerTempurl(Base):
|
||||||
|
@ -1424,3 +1424,13 @@ def attach_fake_replication_rpc(rpc, replicate_hook=None, errors=None):
|
|||||||
return resp
|
return resp
|
||||||
|
|
||||||
return FakeReplConnection
|
return FakeReplConnection
|
||||||
|
|
||||||
|
|
||||||
|
def group_by_byte(contents):
|
||||||
|
# This looks a little funny, but iterating through a byte string on py3
|
||||||
|
# yields a sequence of ints, not a sequence of single-byte byte strings
|
||||||
|
# as it did on py2.
|
||||||
|
byte_iter = (contents[i:i + 1] for i in range(len(contents)))
|
||||||
|
return [
|
||||||
|
(char, sum(1 for _ in grp))
|
||||||
|
for char, grp in itertools.groupby(byte_iter)]
|
||||||
|
@ -415,6 +415,9 @@ class TestSymlinkMiddleware(TestSymlinkMiddlewareBase):
|
|||||||
do_test(
|
do_test(
|
||||||
{'X-Symlink-Target': 'cont/obj',
|
{'X-Symlink-Target': 'cont/obj',
|
||||||
'X-Symlink-Target-Account': target})
|
'X-Symlink-Target-Account': target})
|
||||||
|
do_test(
|
||||||
|
{'X-Symlink-Target': 'cont/obj',
|
||||||
|
'X-Symlink-Target-Account': swob.wsgi_quote(target)})
|
||||||
|
|
||||||
def test_check_symlink_header_invalid_format(self):
|
def test_check_symlink_header_invalid_format(self):
|
||||||
def do_test(headers, status, err_msg):
|
def do_test(headers, status, err_msg):
|
||||||
@ -456,26 +459,25 @@ class TestSymlinkMiddleware(TestSymlinkMiddlewareBase):
|
|||||||
'412 Precondition Failed',
|
'412 Precondition Failed',
|
||||||
b'Account name cannot contain slashes')
|
b'Account name cannot contain slashes')
|
||||||
# with multi-bytes
|
# with multi-bytes
|
||||||
|
target = u'/\u30b0\u30e9\u30d6\u30eb/\u30a2\u30ba\u30ec\u30f3'
|
||||||
|
target = swob.bytes_to_wsgi(target.encode('utf8'))
|
||||||
do_test(
|
do_test(
|
||||||
{'X-Symlink-Target':
|
{'X-Symlink-Target': target},
|
||||||
u'/\u30b0\u30e9\u30d6\u30eb/\u30a2\u30ba\u30ec\u30f3'},
|
|
||||||
'412 Precondition Failed',
|
'412 Precondition Failed',
|
||||||
b'X-Symlink-Target header must be of the '
|
b'X-Symlink-Target header must be of the '
|
||||||
b'form <container name>/<object name>')
|
b'form <container name>/<object name>')
|
||||||
target = u'/\u30b0\u30e9\u30d6\u30eb/\u30a2\u30ba\u30ec\u30f3'
|
|
||||||
target = swob.bytes_to_wsgi(target.encode('utf8'))
|
|
||||||
do_test(
|
do_test(
|
||||||
{'X-Symlink-Target': swob.wsgi_quote(target)},
|
{'X-Symlink-Target': swob.wsgi_quote(target)},
|
||||||
'412 Precondition Failed',
|
'412 Precondition Failed',
|
||||||
b'X-Symlink-Target header must be of the '
|
b'X-Symlink-Target header must be of the '
|
||||||
b'form <container name>/<object name>')
|
b'form <container name>/<object name>')
|
||||||
account = u'\u30b0\u30e9\u30d6\u30eb/\u30a2\u30ba\u30ec\u30f3'
|
account = u'\u30b0\u30e9\u30d6\u30eb/\u30a2\u30ba\u30ec\u30f3'
|
||||||
|
account = swob.bytes_to_wsgi(account.encode('utf8'))
|
||||||
do_test(
|
do_test(
|
||||||
{'X-Symlink-Target': 'c/o',
|
{'X-Symlink-Target': 'c/o',
|
||||||
'X-Symlink-Target-Account': account},
|
'X-Symlink-Target-Account': account},
|
||||||
'412 Precondition Failed',
|
'412 Precondition Failed',
|
||||||
b'Account name cannot contain slashes')
|
b'Account name cannot contain slashes')
|
||||||
account = swob.bytes_to_wsgi(account.encode('utf8'))
|
|
||||||
do_test(
|
do_test(
|
||||||
{'X-Symlink-Target': 'c/o',
|
{'X-Symlink-Target': 'c/o',
|
||||||
'X-Symlink-Target-Account': swob.wsgi_quote(account)},
|
'X-Symlink-Target-Account': swob.wsgi_quote(account)},
|
||||||
|
1
tox.ini
1
tox.ini
@ -129,6 +129,7 @@ basepython = python3
|
|||||||
commands =
|
commands =
|
||||||
pip install -U eventlet@git+https://github.com/eventlet/eventlet.git
|
pip install -U eventlet@git+https://github.com/eventlet/eventlet.git
|
||||||
nosetests {posargs: \
|
nosetests {posargs: \
|
||||||
|
test/functional/test_symlink.py \
|
||||||
test/functional/tests.py}
|
test/functional/tests.py}
|
||||||
|
|
||||||
[testenv:func-encryption]
|
[testenv:func-encryption]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user