Refactor path splitting and validation.

The account, container, and object servers all do the same thing at
the top of GET/PUT/etc.: they split the path, validate that the first
two components are a good (device, partition) pair, and return a 400
if they're not. The object server already had a module-local helper
function for this, but the account and container servers just had
duplicate boilerplate code. Now it's all in one common helper.

Change-Id: I9a20d37fc9e1a68b10149a7aa78cb9691fc04ea9
This commit is contained in:
Samuel Merritt
2013-08-16 16:24:00 -07:00
parent 3dfc094662
commit 61a8a9af18
7 changed files with 384 additions and 403 deletions

View File

@@ -25,10 +25,11 @@ from eventlet import Timeout
import swift.common.db import swift.common.db
from swift.account.utils import account_listing_response from swift.account.utils import account_listing_response
from swift.common.db import AccountBroker, DatabaseConnectionError from swift.common.db import AccountBroker, DatabaseConnectionError
from swift.common.request_helpers import get_param, get_listing_content_type from swift.common.request_helpers import get_param, get_listing_content_type, \
split_and_validate_path
from swift.common.utils import get_logger, hash_path, public, \ from swift.common.utils import get_logger, hash_path, public, \
normalize_timestamp, storage_directory, config_true_value, \ normalize_timestamp, storage_directory, config_true_value, \
validate_device_partition, json, timing_stats, replication json, timing_stats, replication
from swift.common.constraints import ACCOUNT_LISTING_LIMIT, \ from swift.common.constraints import ACCOUNT_LISTING_LIMIT, \
check_mount, check_float, check_utf8 check_mount, check_float, check_utf8
from swift.common.db_replicator import ReplicatorRpc from swift.common.db_replicator import ReplicatorRpc
@@ -87,12 +88,7 @@ class AccountController(object):
@timing_stats() @timing_stats()
def DELETE(self, req): def DELETE(self, req):
"""Handle HTTP DELETE request.""" """Handle HTTP DELETE request."""
try: drive, part, account = split_and_validate_path(req, 3)
drive, part, account = req.split_path(3)
validate_device_partition(drive, part)
except ValueError, err:
return HTTPBadRequest(body=str(err), content_type='text/plain',
request=req)
if self.mount_check and not check_mount(self.root, drive): if self.mount_check and not check_mount(self.root, drive):
return HTTPInsufficientStorage(drive=drive, request=req) return HTTPInsufficientStorage(drive=drive, request=req)
if 'x-timestamp' not in req.headers or \ if 'x-timestamp' not in req.headers or \
@@ -109,12 +105,7 @@ class AccountController(object):
@timing_stats() @timing_stats()
def PUT(self, req): def PUT(self, req):
"""Handle HTTP PUT request.""" """Handle HTTP PUT request."""
try: drive, part, account, container = split_and_validate_path(req, 3, 4)
drive, part, account, container = req.split_path(3, 4)
validate_device_partition(drive, part)
except ValueError, err:
return HTTPBadRequest(body=str(err), content_type='text/plain',
request=req)
if self.mount_check and not check_mount(self.root, drive): if self.mount_check and not check_mount(self.root, drive):
return HTTPInsufficientStorage(drive=drive, request=req) return HTTPInsufficientStorage(drive=drive, request=req)
if container: # put account container if container: # put account container
@@ -174,12 +165,7 @@ class AccountController(object):
@timing_stats() @timing_stats()
def HEAD(self, req): def HEAD(self, req):
"""Handle HTTP HEAD request.""" """Handle HTTP HEAD request."""
try: drive, part, account = split_and_validate_path(req, 3)
drive, part, account = req.split_path(3)
validate_device_partition(drive, part)
except ValueError, err:
return HTTPBadRequest(body=str(err), content_type='text/plain',
request=req)
out_content_type = get_listing_content_type(req) out_content_type = get_listing_content_type(req)
if self.mount_check and not check_mount(self.root, drive): if self.mount_check and not check_mount(self.root, drive):
return HTTPInsufficientStorage(drive=drive, request=req) return HTTPInsufficientStorage(drive=drive, request=req)
@@ -205,12 +191,7 @@ class AccountController(object):
@timing_stats() @timing_stats()
def GET(self, req): def GET(self, req):
"""Handle HTTP GET request.""" """Handle HTTP GET request."""
try: drive, part, account = split_and_validate_path(req, 3)
drive, part, account = req.split_path(3)
validate_device_partition(drive, part)
except ValueError, err:
return HTTPBadRequest(body=str(err), content_type='text/plain',
request=req)
prefix = get_param(req, 'prefix') prefix = get_param(req, 'prefix')
delimiter = get_param(req, 'delimiter') delimiter = get_param(req, 'delimiter')
if delimiter and (len(delimiter) > 1 or ord(delimiter) > 254): if delimiter and (len(delimiter) > 1 or ord(delimiter) > 254):
@@ -247,13 +228,8 @@ class AccountController(object):
Handle HTTP REPLICATE request. Handle HTTP REPLICATE request.
Handler for RPC calls for account replication. Handler for RPC calls for account replication.
""" """
try: post_args = split_and_validate_path(req, 3)
post_args = req.split_path(3) drive, partition, hash = post_args
drive, partition, hash = post_args
validate_device_partition(drive, partition)
except ValueError, err:
return HTTPBadRequest(body=str(err), content_type='text/plain',
request=req)
if self.mount_check and not check_mount(self.root, drive): if self.mount_check and not check_mount(self.root, drive):
return HTTPInsufficientStorage(drive=drive, request=req) return HTTPInsufficientStorage(drive=drive, request=req)
try: try:
@@ -268,12 +244,7 @@ class AccountController(object):
@timing_stats() @timing_stats()
def POST(self, req): def POST(self, req):
"""Handle HTTP POST request.""" """Handle HTTP POST request."""
try: drive, part, account = split_and_validate_path(req, 3)
drive, part, account = req.split_path(3)
validate_device_partition(drive, part)
except ValueError, err:
return HTTPBadRequest(body=str(err), content_type='text/plain',
request=req)
if 'x-timestamp' not in req.headers or \ if 'x-timestamp' not in req.headers or \
not check_float(req.headers['x-timestamp']): not check_float(req.headers['x-timestamp']):
return HTTPBadRequest(body='Missing or bad timestamp', return HTTPBadRequest(body='Missing or bad timestamp',

View File

@@ -22,6 +22,8 @@ from swob in here without creating circular imports.
from swift.common.constraints import FORMAT2CONTENT_TYPE from swift.common.constraints import FORMAT2CONTENT_TYPE
from swift.common.swob import HTTPBadRequest, HTTPNotAcceptable from swift.common.swob import HTTPBadRequest, HTTPNotAcceptable
from swift.common.utils import split_path, validate_device_partition
from urllib import unquote
def get_param(req, name, default=None): def get_param(req, name, default=None):
@@ -67,3 +69,21 @@ def get_listing_content_type(req):
if not out_content_type: if not out_content_type:
raise HTTPNotAcceptable(request=req) raise HTTPNotAcceptable(request=req)
return out_content_type return out_content_type
def split_and_validate_path(request, minsegs=1, maxsegs=None,
rest_with_last=False):
"""
Utility function to split and validate the request path.
:returns: result of split_path if everything's okay
:raises: HTTPBadRequest if something's not okay
"""
try:
segs = split_path(unquote(request.path),
minsegs, maxsegs, rest_with_last)
validate_device_partition(segs[0], segs[1])
return segs
except ValueError as err:
raise HTTPBadRequest(body=str(err), request=request,
content_type='text/plain')

View File

@@ -918,7 +918,6 @@ class Request(object):
['a', 'c'] = split_path('/a/c', 1, 2) ['a', 'c'] = split_path('/a/c', 1, 2)
['a', 'c', 'o/r'] = split_path('/a/c/o/r', 1, 3, True) ['a', 'c', 'o/r'] = split_path('/a/c/o/r', 1, 3, True)
:param path: HTTP Request path to be split
:param minsegs: Minimum number of segments to be extracted :param minsegs: Minimum number of segments to be extracted
:param maxsegs: Maximum number of segments to be extracted :param maxsegs: Maximum number of segments to be extracted
:param rest_with_last: If True, trailing data will be returned as part :param rest_with_last: If True, trailing data will be returned as part

View File

@@ -26,11 +26,11 @@ from eventlet import Timeout
import swift.common.db import swift.common.db
from swift.common.db import ContainerBroker from swift.common.db import ContainerBroker
from swift.common.request_helpers import get_param, get_listing_content_type from swift.common.request_helpers import get_param, get_listing_content_type, \
split_and_validate_path
from swift.common.utils import get_logger, hash_path, public, \ from swift.common.utils import get_logger, hash_path, public, \
normalize_timestamp, storage_directory, validate_sync_to, \ normalize_timestamp, storage_directory, validate_sync_to, \
config_true_value, validate_device_partition, json, timing_stats, \ config_true_value, json, timing_stats, replication, parse_content_type
replication, parse_content_type
from swift.common.constraints import CONTAINER_LISTING_LIMIT, \ from swift.common.constraints import CONTAINER_LISTING_LIMIT, \
check_mount, check_float, check_utf8 check_mount, check_float, check_utf8
from swift.common.bufferedhttp import http_connect from swift.common.bufferedhttp import http_connect
@@ -180,12 +180,8 @@ class ContainerController(object):
@timing_stats() @timing_stats()
def DELETE(self, req): def DELETE(self, req):
"""Handle HTTP DELETE request.""" """Handle HTTP DELETE request."""
try: drive, part, account, container, obj = split_and_validate_path(
drive, part, account, container, obj = req.split_path(4, 5, True) req, 4, 5, True)
validate_device_partition(drive, part)
except ValueError, err:
return HTTPBadRequest(body=str(err), content_type='text/plain',
request=req)
if 'x-timestamp' not in req.headers or \ if 'x-timestamp' not in req.headers or \
not check_float(req.headers['x-timestamp']): not check_float(req.headers['x-timestamp']):
return HTTPBadRequest(body='Missing timestamp', request=req, return HTTPBadRequest(body='Missing timestamp', request=req,
@@ -225,12 +221,8 @@ class ContainerController(object):
@timing_stats() @timing_stats()
def PUT(self, req): def PUT(self, req):
"""Handle HTTP PUT request.""" """Handle HTTP PUT request."""
try: drive, part, account, container, obj = split_and_validate_path(
drive, part, account, container, obj = req.split_path(4, 5, True) req, 4, 5, True)
validate_device_partition(drive, part)
except ValueError, err:
return HTTPBadRequest(body=str(err), content_type='text/plain',
request=req)
if 'x-timestamp' not in req.headers or \ if 'x-timestamp' not in req.headers or \
not check_float(req.headers['x-timestamp']): not check_float(req.headers['x-timestamp']):
return HTTPBadRequest(body='Missing timestamp', request=req, return HTTPBadRequest(body='Missing timestamp', request=req,
@@ -294,12 +286,8 @@ class ContainerController(object):
@timing_stats(sample_rate=0.1) @timing_stats(sample_rate=0.1)
def HEAD(self, req): def HEAD(self, req):
"""Handle HTTP HEAD request.""" """Handle HTTP HEAD request."""
try: drive, part, account, container, obj = split_and_validate_path(
drive, part, account, container, obj = req.split_path(4, 5, True) req, 4, 5, True)
validate_device_partition(drive, part)
except ValueError, err:
return HTTPBadRequest(body=str(err), content_type='text/plain',
request=req)
out_content_type = get_listing_content_type(req) out_content_type = get_listing_content_type(req)
if self.mount_check and not check_mount(self.root, drive): if self.mount_check and not check_mount(self.root, drive):
return HTTPInsufficientStorage(drive=drive, request=req) return HTTPInsufficientStorage(drive=drive, request=req)
@@ -359,12 +347,8 @@ class ContainerController(object):
@timing_stats() @timing_stats()
def GET(self, req): def GET(self, req):
"""Handle HTTP GET request.""" """Handle HTTP GET request."""
try: drive, part, account, container, obj = split_and_validate_path(
drive, part, account, container, obj = req.split_path(4, 5, True) req, 4, 5, True)
validate_device_partition(drive, part)
except ValueError, err:
return HTTPBadRequest(body=str(err), content_type='text/plain',
request=req)
path = get_param(req, 'path') path = get_param(req, 'path')
prefix = get_param(req, 'prefix') prefix = get_param(req, 'prefix')
delimiter = get_param(req, 'delimiter') delimiter = get_param(req, 'delimiter')
@@ -438,13 +422,8 @@ class ContainerController(object):
""" """
Handle HTTP REPLICATE request (json-encoded RPC calls for replication.) Handle HTTP REPLICATE request (json-encoded RPC calls for replication.)
""" """
try: post_args = split_and_validate_path(req, 3)
post_args = req.split_path(3) drive, partition, hash = post_args
drive, partition, hash = post_args
validate_device_partition(drive, partition)
except ValueError, err:
return HTTPBadRequest(body=str(err), content_type='text/plain',
request=req)
if self.mount_check and not check_mount(self.root, drive): if self.mount_check and not check_mount(self.root, drive):
return HTTPInsufficientStorage(drive=drive, request=req) return HTTPInsufficientStorage(drive=drive, request=req)
try: try:
@@ -459,12 +438,7 @@ class ContainerController(object):
@timing_stats() @timing_stats()
def POST(self, req): def POST(self, req):
"""Handle HTTP POST request.""" """Handle HTTP POST request."""
try: drive, part, account, container = split_and_validate_path(req, 4)
drive, part, account, container = req.split_path(4)
validate_device_partition(drive, part)
except ValueError, err:
return HTTPBadRequest(body=str(err), content_type='text/plain',
request=req)
if 'x-timestamp' not in req.headers or \ if 'x-timestamp' not in req.headers or \
not check_float(req.headers['x-timestamp']): not check_float(req.headers['x-timestamp']):
return HTTPBadRequest(body='Missing or bad timestamp', return HTTPBadRequest(body='Missing or bad timestamp',

View File

@@ -24,13 +24,11 @@ from collections import defaultdict
from datetime import datetime from datetime import datetime
from gettext import gettext as _ from gettext import gettext as _
from hashlib import md5 from hashlib import md5
from urllib import unquote
from eventlet import sleep, Timeout from eventlet import sleep, Timeout
from swift.common.utils import mkdirs, normalize_timestamp, public, \ from swift.common.utils import mkdirs, normalize_timestamp, public, \
hash_path, split_path, get_logger, write_pickle, \ hash_path, get_logger, write_pickle, config_true_value, timing_stats, \
config_true_value, validate_device_partition, timing_stats, \
ThreadPool, replication ThreadPool, replication
from swift.common.bufferedhttp import http_connect from swift.common.bufferedhttp import http_connect
from swift.common.constraints import check_object_creation, check_mount, \ from swift.common.constraints import check_object_creation, check_mount, \
@@ -39,6 +37,7 @@ from swift.common.exceptions import ConnectionTimeout, DiskFileError, \
DiskFileNotExist, DiskFileCollision, DiskFileNoSpace, \ DiskFileNotExist, DiskFileCollision, DiskFileNoSpace, \
DiskFileDeviceUnavailable DiskFileDeviceUnavailable
from swift.common.http import is_success from swift.common.http import is_success
from swift.common.request_helpers import split_and_validate_path
from swift.common.swob import HTTPAccepted, HTTPBadRequest, HTTPCreated, \ from swift.common.swob import HTTPAccepted, HTTPBadRequest, HTTPCreated, \
HTTPInternalServerError, HTTPNoContent, HTTPNotFound, HTTPNotModified, \ HTTPInternalServerError, HTTPNoContent, HTTPNotFound, HTTPNotModified, \
HTTPPreconditionFailed, HTTPRequestTimeout, HTTPUnprocessableEntity, \ HTTPPreconditionFailed, HTTPRequestTimeout, HTTPUnprocessableEntity, \
@@ -54,22 +53,6 @@ ASYNCDIR = 'async_pending'
MAX_OBJECT_NAME_LENGTH = 1024 MAX_OBJECT_NAME_LENGTH = 1024
def _parse_path(request, minsegs=5, maxsegs=5):
"""
Utility function to split and validate the request path.
:returns: result of split_path if everything's okay
:raises: HTTPBadRequest if something's not okay
"""
try:
segs = split_path(unquote(request.path), minsegs, maxsegs, True)
validate_device_partition(segs[0], segs[1])
return segs
except ValueError as err:
raise HTTPBadRequest(body=str(err), request=request,
content_type='text/plain')
class ObjectController(object): class ObjectController(object):
"""Implements the WSGI application for the Swift Object Server.""" """Implements the WSGI application for the Swift Object Server."""
@@ -299,7 +282,8 @@ class ObjectController(object):
@timing_stats() @timing_stats()
def POST(self, request): def POST(self, request):
"""Handle HTTP POST requests for the Swift Object Server.""" """Handle HTTP POST requests for the Swift Object Server."""
device, partition, account, container, obj = _parse_path(request) device, partition, account, container, obj = \
split_and_validate_path(request, 5, 5, True)
if 'x-timestamp' not in request.headers or \ if 'x-timestamp' not in request.headers or \
not check_float(request.headers['x-timestamp']): not check_float(request.headers['x-timestamp']):
@@ -346,7 +330,8 @@ class ObjectController(object):
@timing_stats() @timing_stats()
def PUT(self, request): def PUT(self, request):
"""Handle HTTP PUT requests for the Swift Object Server.""" """Handle HTTP PUT requests for the Swift Object Server."""
device, partition, account, container, obj = _parse_path(request) device, partition, account, container, obj = \
split_and_validate_path(request, 5, 5, True)
if 'x-timestamp' not in request.headers or \ if 'x-timestamp' not in request.headers or \
not check_float(request.headers['x-timestamp']): not check_float(request.headers['x-timestamp']):
@@ -442,8 +427,8 @@ class ObjectController(object):
@timing_stats() @timing_stats()
def GET(self, request): def GET(self, request):
"""Handle HTTP GET requests for the Swift Object Server.""" """Handle HTTP GET requests for the Swift Object Server."""
device, partition, account, container, obj = _parse_path(request) device, partition, account, container, obj = \
split_and_validate_path(request, 5, 5, True)
try: try:
disk_file = self._diskfile(device, partition, account, container, disk_file = self._diskfile(device, partition, account, container,
obj, keep_data_fp=True, iter_hook=sleep) obj, keep_data_fp=True, iter_hook=sleep)
@@ -516,8 +501,8 @@ class ObjectController(object):
@timing_stats(sample_rate=0.8) @timing_stats(sample_rate=0.8)
def HEAD(self, request): def HEAD(self, request):
"""Handle HTTP HEAD requests for the Swift Object Server.""" """Handle HTTP HEAD requests for the Swift Object Server."""
device, partition, account, container, obj = _parse_path(request) device, partition, account, container, obj = \
split_and_validate_path(request, 5, 5, True)
try: try:
disk_file = self._diskfile(device, partition, account, container, disk_file = self._diskfile(device, partition, account, container,
obj) obj)
@@ -550,8 +535,8 @@ class ObjectController(object):
@timing_stats() @timing_stats()
def DELETE(self, request): def DELETE(self, request):
"""Handle HTTP DELETE requests for the Swift Object Server.""" """Handle HTTP DELETE requests for the Swift Object Server."""
device, partition, account, container, obj = _parse_path(request) device, partition, account, container, obj = \
split_and_validate_path(request, 5, 5, True)
if 'x-timestamp' not in request.headers or \ if 'x-timestamp' not in request.headers or \
not check_float(request.headers['x-timestamp']): not check_float(request.headers['x-timestamp']):
return HTTPBadRequest(body='Missing timestamp', request=request, return HTTPBadRequest(body='Missing timestamp', request=request,
@@ -599,7 +584,8 @@ class ObjectController(object):
Handle REPLICATE requests for the Swift Object Server. This is used Handle REPLICATE requests for the Swift Object Server. This is used
by the object replicator to get hashes for directories. by the object replicator to get hashes for directories.
""" """
device, partition, suffix = _parse_path(request, 2, 3) device, partition, suffix = split_and_validate_path(
request, 2, 3, True)
if self.mount_check and not check_mount(self.devices, device): if self.mount_check and not check_mount(self.devices, device):
return HTTPInsufficientStorage(drive=device, request=request) return HTTPInsufficientStorage(drive=device, request=request)

File diff suppressed because it is too large Load Diff

View File

@@ -157,18 +157,18 @@ class TestContainerController(unittest.TestCase):
def test_PUT(self): def test_PUT(self):
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT', req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT',
'HTTP_X_TIMESTAMP': '1'}) 'HTTP_X_TIMESTAMP': '1'})
resp = self.controller.PUT(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 201) self.assertEquals(resp.status_int, 201)
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT', req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT',
'HTTP_X_TIMESTAMP': '2'}) 'HTTP_X_TIMESTAMP': '2'})
resp = self.controller.PUT(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 202) self.assertEquals(resp.status_int, 202)
def test_PUT_obj_not_found(self): def test_PUT_obj_not_found(self):
req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'PUT'}, req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
headers={'X-Timestamp': '1', 'X-Size': '0', headers={'X-Timestamp': '1', 'X-Size': '0',
'X-Content-Type': 'text/plain', 'X-ETag': 'e'}) 'X-Content-Type': 'text/plain', 'X-ETag': 'e'})
resp = self.controller.PUT(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 404) self.assertEquals(resp.status_int, 404)
def test_PUT_GET_metadata(self): def test_PUT_GET_metadata(self):
@@ -176,20 +176,20 @@ class TestContainerController(unittest.TestCase):
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT'}, req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT'},
headers={'X-Timestamp': normalize_timestamp(1), headers={'X-Timestamp': normalize_timestamp(1),
'X-Container-Meta-Test': 'Value'}) 'X-Container-Meta-Test': 'Value'})
resp = self.controller.PUT(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 201) self.assertEquals(resp.status_int, 201)
req = Request.blank('/sda1/p/a/c') req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'GET'})
resp = self.controller.GET(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 204) self.assertEquals(resp.status_int, 204)
self.assertEquals(resp.headers.get('x-container-meta-test'), 'Value') self.assertEquals(resp.headers.get('x-container-meta-test'), 'Value')
# Set another metadata header, ensuring old one doesn't disappear # Set another metadata header, ensuring old one doesn't disappear
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'POST'}, req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'POST'},
headers={'X-Timestamp': normalize_timestamp(1), headers={'X-Timestamp': normalize_timestamp(1),
'X-Container-Meta-Test2': 'Value2'}) 'X-Container-Meta-Test2': 'Value2'})
resp = self.controller.POST(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 204) self.assertEquals(resp.status_int, 204)
req = Request.blank('/sda1/p/a/c') req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'GET'})
resp = self.controller.GET(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 204) self.assertEquals(resp.status_int, 204)
self.assertEquals(resp.headers.get('x-container-meta-test'), 'Value') self.assertEquals(resp.headers.get('x-container-meta-test'), 'Value')
self.assertEquals(resp.headers.get('x-container-meta-test2'), 'Value2') self.assertEquals(resp.headers.get('x-container-meta-test2'), 'Value2')
@@ -197,10 +197,10 @@ class TestContainerController(unittest.TestCase):
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT'}, req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT'},
headers={'X-Timestamp': normalize_timestamp(3), headers={'X-Timestamp': normalize_timestamp(3),
'X-Container-Meta-Test': 'New Value'}) 'X-Container-Meta-Test': 'New Value'})
resp = self.controller.PUT(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 202) self.assertEquals(resp.status_int, 202)
req = Request.blank('/sda1/p/a/c') req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'GET'})
resp = self.controller.GET(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 204) self.assertEquals(resp.status_int, 204)
self.assertEquals(resp.headers.get('x-container-meta-test'), self.assertEquals(resp.headers.get('x-container-meta-test'),
'New Value') 'New Value')
@@ -208,10 +208,10 @@ class TestContainerController(unittest.TestCase):
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT'}, req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT'},
headers={'X-Timestamp': normalize_timestamp(2), headers={'X-Timestamp': normalize_timestamp(2),
'X-Container-Meta-Test': 'Old Value'}) 'X-Container-Meta-Test': 'Old Value'})
resp = self.controller.PUT(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 202) self.assertEquals(resp.status_int, 202)
req = Request.blank('/sda1/p/a/c') req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'GET'})
resp = self.controller.GET(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 204) self.assertEquals(resp.status_int, 204)
self.assertEquals(resp.headers.get('x-container-meta-test'), self.assertEquals(resp.headers.get('x-container-meta-test'),
'New Value') 'New Value')
@@ -219,26 +219,26 @@ class TestContainerController(unittest.TestCase):
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT'}, req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT'},
headers={'X-Timestamp': normalize_timestamp(4), headers={'X-Timestamp': normalize_timestamp(4),
'X-Container-Meta-Test': ''}) 'X-Container-Meta-Test': ''})
resp = self.controller.PUT(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 202) self.assertEquals(resp.status_int, 202)
req = Request.blank('/sda1/p/a/c') req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'GET'})
resp = self.controller.GET(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 204) self.assertEquals(resp.status_int, 204)
self.assert_('x-container-meta-test' not in resp.headers) self.assert_('x-container-meta-test' not in resp.headers)
def test_PUT_invalid_partition(self): def test_PUT_invalid_partition(self):
req = Request.blank('/sda1/./a/c', environ={'REQUEST_METHOD': 'PUT', req = Request.blank('/sda1/./a/c', environ={'REQUEST_METHOD': 'PUT',
'HTTP_X_TIMESTAMP': '1'}) 'HTTP_X_TIMESTAMP': '1'})
resp = self.controller.PUT(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 400) self.assertEquals(resp.status_int, 400)
def test_PUT_timestamp_not_float(self): def test_PUT_timestamp_not_float(self):
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT', req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT',
'HTTP_X_TIMESTAMP': '0'}) 'HTTP_X_TIMESTAMP': '0'})
self.controller.PUT(req) req.get_response(self.controller)
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT'}, req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT'},
headers={'X-Timestamp': 'not-float'}) headers={'X-Timestamp': 'not-float'})
resp = self.controller.PUT(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 400) self.assertEquals(resp.status_int, 400)
def test_PUT_insufficient_storage(self): def test_PUT_insufficient_storage(self):
@@ -246,19 +246,19 @@ class TestContainerController(unittest.TestCase):
{'devices': self.testdir}) {'devices': self.testdir})
req = Request.blank('/sda-null/p/a/c', environ={'REQUEST_METHOD': 'PUT', req = Request.blank('/sda-null/p/a/c', environ={'REQUEST_METHOD': 'PUT',
'HTTP_X_TIMESTAMP': '1'}) 'HTTP_X_TIMESTAMP': '1'})
resp = self.controller.PUT(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 507) self.assertEquals(resp.status_int, 507)
def test_POST_HEAD_metadata(self): def test_POST_HEAD_metadata(self):
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT'}, req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT'},
headers={'X-Timestamp': normalize_timestamp(1)}) headers={'X-Timestamp': normalize_timestamp(1)})
resp = self.controller.PUT(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 201) self.assertEquals(resp.status_int, 201)
# Set metadata header # Set metadata header
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'POST'}, req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'POST'},
headers={'X-Timestamp': normalize_timestamp(1), headers={'X-Timestamp': normalize_timestamp(1),
'X-Container-Meta-Test': 'Value'}) 'X-Container-Meta-Test': 'Value'})
resp = self.controller.POST(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 204) self.assertEquals(resp.status_int, 204)
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'HEAD'}) req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'HEAD'})
resp = req.get_response(self.controller) resp = req.get_response(self.controller)
@@ -268,7 +268,7 @@ class TestContainerController(unittest.TestCase):
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'POST'}, req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'POST'},
headers={'X-Timestamp': normalize_timestamp(3), headers={'X-Timestamp': normalize_timestamp(3),
'X-Container-Meta-Test': 'New Value'}) 'X-Container-Meta-Test': 'New Value'})
resp = self.controller.POST(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 204) self.assertEquals(resp.status_int, 204)
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'HEAD'}) req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'HEAD'})
resp = req.get_response(self.controller) resp = req.get_response(self.controller)
@@ -279,7 +279,7 @@ class TestContainerController(unittest.TestCase):
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'POST'}, req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'POST'},
headers={'X-Timestamp': normalize_timestamp(2), headers={'X-Timestamp': normalize_timestamp(2),
'X-Container-Meta-Test': 'Old Value'}) 'X-Container-Meta-Test': 'Old Value'})
resp = self.controller.POST(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 204) self.assertEquals(resp.status_int, 204)
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'HEAD'}) req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'HEAD'})
resp = req.get_response(self.controller) resp = req.get_response(self.controller)
@@ -290,7 +290,7 @@ class TestContainerController(unittest.TestCase):
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'POST'}, req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'POST'},
headers={'X-Timestamp': normalize_timestamp(4), headers={'X-Timestamp': normalize_timestamp(4),
'X-Container-Meta-Test': ''}) 'X-Container-Meta-Test': ''})
resp = self.controller.POST(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 204) self.assertEquals(resp.status_int, 204)
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'HEAD'}) req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'HEAD'})
resp = req.get_response(self.controller) resp = req.get_response(self.controller)
@@ -306,7 +306,7 @@ class TestContainerController(unittest.TestCase):
def test_POST_timestamp_not_float(self): def test_POST_timestamp_not_float(self):
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT', req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT',
'HTTP_X_TIMESTAMP': '0'}) 'HTTP_X_TIMESTAMP': '0'})
self.controller.PUT(req) req.get_response(self.controller)
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'POST'}, req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'POST'},
headers={'X-Timestamp': 'not-float'}) headers={'X-Timestamp': 'not-float'})
resp = req.get_response(self.controller) resp = req.get_response(self.controller)
@@ -348,17 +348,17 @@ class TestContainerController(unittest.TestCase):
req = Request.blank('/sda1/p/a/c/o', req = Request.blank('/sda1/p/a/c/o',
environ={'REQUEST_METHOD': 'DELETE'}, environ={'REQUEST_METHOD': 'DELETE'},
headers={'X-Timestamp': '1'}) headers={'X-Timestamp': '1'})
resp = self.controller.DELETE(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 404) self.assertEquals(resp.status_int, 404)
def test_DELETE_container_not_found(self): def test_DELETE_container_not_found(self):
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT', req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT',
'HTTP_X_TIMESTAMP': '0'}) 'HTTP_X_TIMESTAMP': '0'})
resp = self.controller.PUT(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 201) self.assertEquals(resp.status_int, 201)
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'DELETE', req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'DELETE',
'HTTP_X_TIMESTAMP': '1'}) 'HTTP_X_TIMESTAMP': '1'})
resp = self.controller.DELETE(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 404) self.assertEquals(resp.status_int, 404)
def test_PUT_utf8(self): def test_PUT_utf8(self):
@@ -367,7 +367,7 @@ class TestContainerController(unittest.TestCase):
req = Request.blank('/sda1/p/a/%s' % container_name, environ={ req = Request.blank('/sda1/p/a/%s' % container_name, environ={
'REQUEST_METHOD': 'PUT', 'REQUEST_METHOD': 'PUT',
'HTTP_X_TIMESTAMP': '1'}) 'HTTP_X_TIMESTAMP': '1'})
resp = self.controller.PUT(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 201) self.assertEquals(resp.status_int, 201)
def test_account_update_mismatched_host_device(self): def test_account_update_mismatched_host_device(self):
@@ -388,7 +388,8 @@ class TestContainerController(unittest.TestCase):
environ={'REQUEST_METHOD': 'PUT', environ={'REQUEST_METHOD': 'PUT',
'HTTP_X_TIMESTAMP': '1'}, 'HTTP_X_TIMESTAMP': '1'},
headers={'X-Timestamp': '0000000001.00000', headers={'X-Timestamp': '0000000001.00000',
'X-Account-Host': '%s:%s' % bindsock.getsockname(), 'X-Account-Host': '%s:%s' %
bindsock.getsockname(),
'X-Account-Partition': '123', 'X-Account-Partition': '123',
'X-Account-Device': 'sda1', 'X-Account-Device': 'sda1',
'X-Account-Override-Deleted': 'yes'}) 'X-Account-Override-Deleted': 'yes'})
@@ -433,7 +434,7 @@ class TestContainerController(unittest.TestCase):
event = spawn(accept, 201, '0000000001.00000') event = spawn(accept, 201, '0000000001.00000')
try: try:
with Timeout(3): with Timeout(3):
resp = self.controller.PUT(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 201) self.assertEquals(resp.status_int, 201)
finally: finally:
err = event.wait() err = event.wait()
@@ -442,7 +443,7 @@ class TestContainerController(unittest.TestCase):
req = Request.blank('/sda1/p/a/c', req = Request.blank('/sda1/p/a/c',
environ={'REQUEST_METHOD': 'DELETE'}, environ={'REQUEST_METHOD': 'DELETE'},
headers={'X-Timestamp': '2'}) headers={'X-Timestamp': '2'})
resp = self.controller.DELETE(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 204) self.assertEquals(resp.status_int, 204)
req = Request.blank('/sda1/p/a/c', req = Request.blank('/sda1/p/a/c',
environ={'REQUEST_METHOD': 'PUT'}, environ={'REQUEST_METHOD': 'PUT'},
@@ -453,7 +454,7 @@ class TestContainerController(unittest.TestCase):
event = spawn(accept, 404, '0000000003.00000') event = spawn(accept, 404, '0000000003.00000')
try: try:
with Timeout(3): with Timeout(3):
resp = self.controller.PUT(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 404) self.assertEquals(resp.status_int, 404)
finally: finally:
err = event.wait() err = event.wait()
@@ -469,7 +470,7 @@ class TestContainerController(unittest.TestCase):
got_exc = False got_exc = False
try: try:
with Timeout(3): with Timeout(3):
resp = self.controller.PUT(req) resp = req.get_response(self.controller)
except BaseException, err: except BaseException, err:
got_exc = True got_exc = True
finally: finally:
@@ -482,7 +483,7 @@ class TestContainerController(unittest.TestCase):
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT'}, req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT'},
headers={'x-timestamp': '1', headers={'x-timestamp': '1',
'x-container-sync-to': 'http://127.0.0.1:12345/v1/a/c'}) 'x-container-sync-to': 'http://127.0.0.1:12345/v1/a/c'})
resp = self.controller.PUT(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 201) self.assertEquals(resp.status_int, 201)
db = self.controller._get_container_broker('sda1', 'p', 'a', 'c') db = self.controller._get_container_broker('sda1', 'p', 'a', 'c')
info = db.get_info() info = db.get_info()
@@ -496,7 +497,7 @@ class TestContainerController(unittest.TestCase):
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT'}, req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT'},
headers={'x-timestamp': '1', headers={'x-timestamp': '1',
'x-container-sync-to': 'http://127.0.0.1:12345/v1/a/c'}) 'x-container-sync-to': 'http://127.0.0.1:12345/v1/a/c'})
resp = self.controller.PUT(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 202) self.assertEquals(resp.status_int, 202)
db = self.controller._get_container_broker('sda1', 'p', 'a', 'c') db = self.controller._get_container_broker('sda1', 'p', 'a', 'c')
info = db.get_info() info = db.get_info()
@@ -506,7 +507,7 @@ class TestContainerController(unittest.TestCase):
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT'}, req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT'},
headers={'x-timestamp': '1', headers={'x-timestamp': '1',
'x-container-sync-to': 'http://127.0.0.1:12345/v1/a/c2'}) 'x-container-sync-to': 'http://127.0.0.1:12345/v1/a/c2'})
resp = self.controller.PUT(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 202) self.assertEquals(resp.status_int, 202)
db = self.controller._get_container_broker('sda1', 'p', 'a', 'c') db = self.controller._get_container_broker('sda1', 'p', 'a', 'c')
info = db.get_info() info = db.get_info()
@@ -517,7 +518,7 @@ class TestContainerController(unittest.TestCase):
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT'}, req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT'},
headers={'x-timestamp': '1', headers={'x-timestamp': '1',
'x-container-sync-to': 'http://127.0.0.1:12345/v1/a/c'}) 'x-container-sync-to': 'http://127.0.0.1:12345/v1/a/c'})
resp = self.controller.PUT(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 201) self.assertEquals(resp.status_int, 201)
db = self.controller._get_container_broker('sda1', 'p', 'a', 'c') db = self.controller._get_container_broker('sda1', 'p', 'a', 'c')
info = db.get_info() info = db.get_info()
@@ -531,7 +532,7 @@ class TestContainerController(unittest.TestCase):
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'POST'}, req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'POST'},
headers={'x-timestamp': '1', headers={'x-timestamp': '1',
'x-container-sync-to': 'http://127.0.0.1:12345/v1/a/c'}) 'x-container-sync-to': 'http://127.0.0.1:12345/v1/a/c'})
resp = self.controller.POST(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 204) self.assertEquals(resp.status_int, 204)
db = self.controller._get_container_broker('sda1', 'p', 'a', 'c') db = self.controller._get_container_broker('sda1', 'p', 'a', 'c')
info = db.get_info() info = db.get_info()
@@ -541,7 +542,7 @@ class TestContainerController(unittest.TestCase):
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'POST'}, req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'POST'},
headers={'x-timestamp': '1', headers={'x-timestamp': '1',
'x-container-sync-to': 'http://127.0.0.1:12345/v1/a/c2'}) 'x-container-sync-to': 'http://127.0.0.1:12345/v1/a/c2'})
resp = self.controller.POST(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 204) self.assertEquals(resp.status_int, 204)
db = self.controller._get_container_broker('sda1', 'p', 'a', 'c') db = self.controller._get_container_broker('sda1', 'p', 'a', 'c')
info = db.get_info() info = db.get_info()
@@ -551,15 +552,15 @@ class TestContainerController(unittest.TestCase):
def test_DELETE(self): def test_DELETE(self):
req = Request.blank('/sda1/p/a/c', req = Request.blank('/sda1/p/a/c',
environ={'REQUEST_METHOD': 'PUT'}, headers={'X-Timestamp': '1'}) environ={'REQUEST_METHOD': 'PUT'}, headers={'X-Timestamp': '1'})
resp = self.controller.PUT(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 201) self.assertEquals(resp.status_int, 201)
req = Request.blank('/sda1/p/a/c', req = Request.blank('/sda1/p/a/c',
environ={'REQUEST_METHOD': 'DELETE'}, headers={'X-Timestamp': '2'}) environ={'REQUEST_METHOD': 'DELETE'}, headers={'X-Timestamp': '2'})
resp = self.controller.DELETE(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 204) self.assertEquals(resp.status_int, 204)
req = Request.blank('/sda1/p/a/c', req = Request.blank('/sda1/p/a/c',
environ={'REQUEST_METHOD': 'GET'}, headers={'X-Timestamp': '3'}) environ={'REQUEST_METHOD': 'GET'}, headers={'X-Timestamp': '3'})
resp = self.controller.GET(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 404) self.assertEquals(resp.status_int, 404)
def test_DELETE_not_found(self): def test_DELETE_not_found(self):
@@ -568,35 +569,35 @@ class TestContainerController(unittest.TestCase):
# later. # later.
req = Request.blank('/sda1/p/a/c', req = Request.blank('/sda1/p/a/c',
environ={'REQUEST_METHOD': 'DELETE', 'HTTP_X_TIMESTAMP': '1'}) environ={'REQUEST_METHOD': 'DELETE', 'HTTP_X_TIMESTAMP': '1'})
resp = self.controller.DELETE(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 404) self.assertEquals(resp.status_int, 404)
def test_DELETE_object(self): def test_DELETE_object(self):
req = Request.blank('/sda1/p/a/c', req = Request.blank('/sda1/p/a/c',
environ={'REQUEST_METHOD': 'PUT'}, headers={'X-Timestamp': '2'}) environ={'REQUEST_METHOD': 'PUT'}, headers={'X-Timestamp': '2'})
resp = self.controller.PUT(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 201) self.assertEquals(resp.status_int, 201)
req = Request.blank('/sda1/p/a/c/o', req = Request.blank('/sda1/p/a/c/o',
environ={'REQUEST_METHOD': 'PUT', 'HTTP_X_TIMESTAMP': '0', environ={'REQUEST_METHOD': 'PUT', 'HTTP_X_TIMESTAMP': '0',
'HTTP_X_SIZE': 1, 'HTTP_X_CONTENT_TYPE': 'text/plain', 'HTTP_X_SIZE': 1, 'HTTP_X_CONTENT_TYPE': 'text/plain',
'HTTP_X_ETAG': 'x'}) 'HTTP_X_ETAG': 'x'})
resp = self.controller.PUT(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 201) self.assertEquals(resp.status_int, 201)
req = Request.blank('/sda1/p/a/c', req = Request.blank('/sda1/p/a/c',
environ={'REQUEST_METHOD': 'DELETE'}, headers={'X-Timestamp': '3'}) environ={'REQUEST_METHOD': 'DELETE'}, headers={'X-Timestamp': '3'})
resp = self.controller.DELETE(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 409) self.assertEquals(resp.status_int, 409)
req = Request.blank('/sda1/p/a/c/o', req = Request.blank('/sda1/p/a/c/o',
environ={'REQUEST_METHOD': 'DELETE'}, headers={'X-Timestamp': '4'}) environ={'REQUEST_METHOD': 'DELETE'}, headers={'X-Timestamp': '4'})
resp = self.controller.DELETE(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 204) self.assertEquals(resp.status_int, 204)
req = Request.blank('/sda1/p/a/c', req = Request.blank('/sda1/p/a/c',
environ={'REQUEST_METHOD': 'DELETE'}, headers={'X-Timestamp': '5'}) environ={'REQUEST_METHOD': 'DELETE'}, headers={'X-Timestamp': '5'})
resp = self.controller.DELETE(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 204) self.assertEquals(resp.status_int, 204)
req = Request.blank('/sda1/p/a/c', req = Request.blank('/sda1/p/a/c',
environ={'REQUEST_METHOD': 'GET'}, headers={'X-Timestamp': '6'}) environ={'REQUEST_METHOD': 'GET'}, headers={'X-Timestamp': '6'})
resp = self.controller.GET(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 404) self.assertEquals(resp.status_int, 404)
def test_DELETE_account_update(self): def test_DELETE_account_update(self):
@@ -627,7 +628,7 @@ class TestContainerController(unittest.TestCase):
req = Request.blank('/sda1/p/a/c', req = Request.blank('/sda1/p/a/c',
environ={'REQUEST_METHOD': 'PUT'}, headers={'X-Timestamp': '1'}) environ={'REQUEST_METHOD': 'PUT'}, headers={'X-Timestamp': '1'})
resp = self.controller.PUT(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 201) self.assertEquals(resp.status_int, 201)
req = Request.blank('/sda1/p/a/c', req = Request.blank('/sda1/p/a/c',
environ={'REQUEST_METHOD': 'DELETE'}, environ={'REQUEST_METHOD': 'DELETE'},
@@ -638,7 +639,7 @@ class TestContainerController(unittest.TestCase):
event = spawn(accept, 204, '0000000002.00000') event = spawn(accept, 204, '0000000002.00000')
try: try:
with Timeout(3): with Timeout(3):
resp = self.controller.DELETE(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 204) self.assertEquals(resp.status_int, 204)
finally: finally:
err = event.wait() err = event.wait()
@@ -646,7 +647,7 @@ class TestContainerController(unittest.TestCase):
raise Exception(err) raise Exception(err)
req = Request.blank('/sda1/p/a/c', req = Request.blank('/sda1/p/a/c',
environ={'REQUEST_METHOD': 'PUT', 'HTTP_X_TIMESTAMP': '2'}) environ={'REQUEST_METHOD': 'PUT', 'HTTP_X_TIMESTAMP': '2'})
resp = self.controller.PUT(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 201) self.assertEquals(resp.status_int, 201)
req = Request.blank('/sda1/p/a/c', req = Request.blank('/sda1/p/a/c',
environ={'REQUEST_METHOD': 'DELETE'}, environ={'REQUEST_METHOD': 'DELETE'},
@@ -657,7 +658,7 @@ class TestContainerController(unittest.TestCase):
event = spawn(accept, 404, '0000000003.00000') event = spawn(accept, 404, '0000000003.00000')
try: try:
with Timeout(3): with Timeout(3):
resp = self.controller.DELETE(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 404) self.assertEquals(resp.status_int, 404)
finally: finally:
err = event.wait() err = event.wait()
@@ -665,7 +666,7 @@ class TestContainerController(unittest.TestCase):
raise Exception(err) raise Exception(err)
req = Request.blank('/sda1/p/a/c', req = Request.blank('/sda1/p/a/c',
environ={'REQUEST_METHOD': 'PUT', 'HTTP_X_TIMESTAMP': '4'}) environ={'REQUEST_METHOD': 'PUT', 'HTTP_X_TIMESTAMP': '4'})
resp = self.controller.PUT(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 201) self.assertEquals(resp.status_int, 201)
req = Request.blank('/sda1/p/a/c', req = Request.blank('/sda1/p/a/c',
environ={'REQUEST_METHOD': 'DELETE'}, environ={'REQUEST_METHOD': 'DELETE'},
@@ -677,7 +678,7 @@ class TestContainerController(unittest.TestCase):
got_exc = False got_exc = False
try: try:
with Timeout(3): with Timeout(3):
resp = self.controller.DELETE(req) resp = req.get_response(self.controller)
except BaseException, err: except BaseException, err:
got_exc = True got_exc = True
finally: finally:
@@ -689,16 +690,16 @@ class TestContainerController(unittest.TestCase):
def test_DELETE_invalid_partition(self): def test_DELETE_invalid_partition(self):
req = Request.blank('/sda1/./a/c', environ={'REQUEST_METHOD': 'DELETE', req = Request.blank('/sda1/./a/c', environ={'REQUEST_METHOD': 'DELETE',
'HTTP_X_TIMESTAMP': '1'}) 'HTTP_X_TIMESTAMP': '1'})
resp = self.controller.DELETE(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 400) self.assertEquals(resp.status_int, 400)
def test_DELETE_timestamp_not_float(self): def test_DELETE_timestamp_not_float(self):
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT', req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT',
'HTTP_X_TIMESTAMP': '0'}) 'HTTP_X_TIMESTAMP': '0'})
self.controller.PUT(req) req.get_response(self.controller)
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'DELETE'}, req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'DELETE'},
headers={'X-Timestamp': 'not-float'}) headers={'X-Timestamp': 'not-float'})
resp = self.controller.DELETE(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 400) self.assertEquals(resp.status_int, 400)
def test_DELETE_insufficient_storage(self): def test_DELETE_insufficient_storage(self):
@@ -706,25 +707,25 @@ class TestContainerController(unittest.TestCase):
{'devices': self.testdir}) {'devices': self.testdir})
req = Request.blank('/sda-null/p/a/c', environ={'REQUEST_METHOD': 'DELETE', req = Request.blank('/sda-null/p/a/c', environ={'REQUEST_METHOD': 'DELETE',
'HTTP_X_TIMESTAMP': '1'}) 'HTTP_X_TIMESTAMP': '1'})
resp = self.controller.DELETE(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 507) self.assertEquals(resp.status_int, 507)
def test_GET_over_limit(self): def test_GET_over_limit(self):
req = Request.blank('/sda1/p/a/c?limit=%d' % req = Request.blank('/sda1/p/a/c?limit=%d' %
(container_server.CONTAINER_LISTING_LIMIT + 1), (container_server.CONTAINER_LISTING_LIMIT + 1),
environ={'REQUEST_METHOD': 'GET'}) environ={'REQUEST_METHOD': 'GET'})
resp = self.controller.GET(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 412) self.assertEquals(resp.status_int, 412)
def test_GET_json(self): def test_GET_json(self):
# make a container # make a container
req = Request.blank('/sda1/p/a/jsonc', environ={'REQUEST_METHOD': 'PUT', req = Request.blank('/sda1/p/a/jsonc', environ={'REQUEST_METHOD': 'PUT',
'HTTP_X_TIMESTAMP': '0'}) 'HTTP_X_TIMESTAMP': '0'})
resp = self.controller.PUT(req) resp = req.get_response(self.controller)
# test an empty container # test an empty container
req = Request.blank('/sda1/p/a/jsonc?format=json', req = Request.blank('/sda1/p/a/jsonc?format=json',
environ={'REQUEST_METHOD': 'GET'}) environ={'REQUEST_METHOD': 'GET'})
resp = self.controller.GET(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 200) self.assertEquals(resp.status_int, 200)
self.assertEquals(simplejson.loads(resp.body), []) self.assertEquals(simplejson.loads(resp.body), [])
# fill the container # fill the container
@@ -735,7 +736,7 @@ class TestContainerController(unittest.TestCase):
'HTTP_X_CONTENT_TYPE': 'text/plain', 'HTTP_X_CONTENT_TYPE': 'text/plain',
'HTTP_X_ETAG': 'x', 'HTTP_X_ETAG': 'x',
'HTTP_X_SIZE': 0}) 'HTTP_X_SIZE': 0})
resp = self.controller.PUT(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 201) self.assertEquals(resp.status_int, 201)
# test format # test format
json_body = [{"name":"0", json_body = [{"name":"0",
@@ -756,7 +757,7 @@ class TestContainerController(unittest.TestCase):
req = Request.blank('/sda1/p/a/jsonc?format=json', req = Request.blank('/sda1/p/a/jsonc?format=json',
environ={'REQUEST_METHOD': 'GET'}) environ={'REQUEST_METHOD': 'GET'})
resp = self.controller.GET(req) resp = req.get_response(self.controller)
self.assertEquals(resp.content_type, 'application/json') self.assertEquals(resp.content_type, 'application/json')
self.assertEquals(simplejson.loads(resp.body), json_body) self.assertEquals(simplejson.loads(resp.body), json_body)
self.assertEquals(resp.charset, 'utf-8') self.assertEquals(resp.charset, 'utf-8')
@@ -788,10 +789,10 @@ class TestContainerController(unittest.TestCase):
# make a container # make a container
req = Request.blank('/sda1/p/a/plainc', environ={'REQUEST_METHOD': 'PUT', req = Request.blank('/sda1/p/a/plainc', environ={'REQUEST_METHOD': 'PUT',
'HTTP_X_TIMESTAMP': '0'}) 'HTTP_X_TIMESTAMP': '0'})
resp = self.controller.PUT(req) resp = req.get_response(self.controller)
# test an empty container # test an empty container
req = Request.blank('/sda1/p/a/plainc', environ={'REQUEST_METHOD': 'GET'}) req = Request.blank('/sda1/p/a/plainc', environ={'REQUEST_METHOD': 'GET'})
resp = self.controller.GET(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 204) self.assertEquals(resp.status_int, 204)
# fill the container # fill the container
for i in range(3): for i in range(3):
@@ -801,13 +802,13 @@ class TestContainerController(unittest.TestCase):
'HTTP_X_CONTENT_TYPE': 'text/plain', 'HTTP_X_CONTENT_TYPE': 'text/plain',
'HTTP_X_ETAG': 'x', 'HTTP_X_ETAG': 'x',
'HTTP_X_SIZE': 0}) 'HTTP_X_SIZE': 0})
resp = self.controller.PUT(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 201) self.assertEquals(resp.status_int, 201)
plain_body = '0\n1\n2\n' plain_body = '0\n1\n2\n'
req = Request.blank('/sda1/p/a/plainc', req = Request.blank('/sda1/p/a/plainc',
environ={'REQUEST_METHOD': 'GET'}) environ={'REQUEST_METHOD': 'GET'})
resp = self.controller.GET(req) resp = req.get_response(self.controller)
self.assertEquals(resp.content_type, 'text/plain') self.assertEquals(resp.content_type, 'text/plain')
self.assertEquals(resp.body, plain_body) self.assertEquals(resp.body, plain_body)
self.assertEquals(resp.charset, 'utf-8') self.assertEquals(resp.charset, 'utf-8')
@@ -823,7 +824,7 @@ class TestContainerController(unittest.TestCase):
req = Request.blank('/sda1/p/a/plainc', req = Request.blank('/sda1/p/a/plainc',
environ={'REQUEST_METHOD': 'GET'}) environ={'REQUEST_METHOD': 'GET'})
req.accept = accept req.accept = accept
resp = self.controller.GET(req) resp = req.get_response(self.controller)
self.assertEquals(resp.body, plain_body, self.assertEquals(resp.body, plain_body,
'Invalid body for Accept: %s' % accept) 'Invalid body for Accept: %s' % accept)
self.assertEquals(resp.content_type, 'text/plain', self.assertEquals(resp.content_type, 'text/plain',
@@ -840,14 +841,14 @@ class TestContainerController(unittest.TestCase):
req = Request.blank('/sda1/p/a/plainc?format=plain', req = Request.blank('/sda1/p/a/plainc?format=plain',
environ={'REQUEST_METHOD': 'GET'}) environ={'REQUEST_METHOD': 'GET'})
req.accept = 'application/json' req.accept = 'application/json'
resp = self.controller.GET(req) resp = req.get_response(self.controller)
self.assertEquals(resp.content_type, 'text/plain') self.assertEquals(resp.content_type, 'text/plain')
self.assertEquals(resp.body, plain_body) self.assertEquals(resp.body, plain_body)
# test unknown format uses default plain # test unknown format uses default plain
req = Request.blank('/sda1/p/a/plainc?format=somethingelse', req = Request.blank('/sda1/p/a/plainc?format=somethingelse',
environ={'REQUEST_METHOD': 'GET'}) environ={'REQUEST_METHOD': 'GET'})
resp = self.controller.GET(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 200) self.assertEquals(resp.status_int, 200)
self.assertEquals(resp.content_type, 'text/plain') self.assertEquals(resp.content_type, 'text/plain')
self.assertEquals(resp.body, plain_body) self.assertEquals(resp.body, plain_body)
@@ -857,7 +858,7 @@ class TestContainerController(unittest.TestCase):
req = Request.blank('/sda1/p/a/jsonc', environ={ req = Request.blank('/sda1/p/a/jsonc', environ={
'REQUEST_METHOD': 'PUT', 'REQUEST_METHOD': 'PUT',
'HTTP_X_TIMESTAMP': '0'}) 'HTTP_X_TIMESTAMP': '0'})
resp = self.controller.PUT(req) resp = req.get_response(self.controller)
for i, d in [(0, 1.5), for i, d in [(0, 1.5),
(1, 1.0), ]: (1, 1.0), ]:
req = Request.blank('/sda1/p/a/jsonc/%s' % i, environ={ req = Request.blank('/sda1/p/a/jsonc/%s' % i, environ={
@@ -866,7 +867,7 @@ class TestContainerController(unittest.TestCase):
'HTTP_X_CONTENT_TYPE': 'text/plain', 'HTTP_X_CONTENT_TYPE': 'text/plain',
'HTTP_X_ETAG': 'x', 'HTTP_X_ETAG': 'x',
'HTTP_X_SIZE': 0}) 'HTTP_X_SIZE': 0})
resp = self.controller.PUT(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 201) self.assertEquals(resp.status_int, 201)
# test format # test format
# last_modified format must be uniform, even when there are not msecs # last_modified format must be uniform, even when there are not msecs
@@ -883,7 +884,7 @@ class TestContainerController(unittest.TestCase):
req = Request.blank('/sda1/p/a/jsonc?format=json', req = Request.blank('/sda1/p/a/jsonc?format=json',
environ={'REQUEST_METHOD': 'GET'}) environ={'REQUEST_METHOD': 'GET'})
resp = self.controller.GET(req) resp = req.get_response(self.controller)
self.assertEquals(resp.content_type, 'application/json') self.assertEquals(resp.content_type, 'application/json')
self.assertEquals(simplejson.loads(resp.body), json_body) self.assertEquals(simplejson.loads(resp.body), json_body)
self.assertEquals(resp.charset, 'utf-8') self.assertEquals(resp.charset, 'utf-8')
@@ -892,7 +893,7 @@ class TestContainerController(unittest.TestCase):
# make a container # make a container
req = Request.blank('/sda1/p/a/xmlc', environ={'REQUEST_METHOD': 'PUT', req = Request.blank('/sda1/p/a/xmlc', environ={'REQUEST_METHOD': 'PUT',
'HTTP_X_TIMESTAMP': '0'}) 'HTTP_X_TIMESTAMP': '0'})
resp = self.controller.PUT(req) resp = req.get_response(self.controller)
# fill the container # fill the container
for i in range(3): for i in range(3):
req = Request.blank('/sda1/p/a/xmlc/%s' % i, req = Request.blank('/sda1/p/a/xmlc/%s' % i,
@@ -902,7 +903,7 @@ class TestContainerController(unittest.TestCase):
'HTTP_X_CONTENT_TYPE': 'text/plain', 'HTTP_X_CONTENT_TYPE': 'text/plain',
'HTTP_X_ETAG': 'x', 'HTTP_X_ETAG': 'x',
'HTTP_X_SIZE': 0}) 'HTTP_X_SIZE': 0})
resp = self.controller.PUT(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 201) self.assertEquals(resp.status_int, 201)
xml_body = "<?xml version='1.0' encoding='UTF-8'?>\n" \ xml_body = "<?xml version='1.0' encoding='UTF-8'?>\n" \
'<container name="xmlc">' \ '<container name="xmlc">' \
@@ -923,7 +924,7 @@ class TestContainerController(unittest.TestCase):
# tests # tests
req = Request.blank('/sda1/p/a/xmlc?format=xml', req = Request.blank('/sda1/p/a/xmlc?format=xml',
environ={'REQUEST_METHOD': 'GET'}) environ={'REQUEST_METHOD': 'GET'})
resp = self.controller.GET(req) resp = req.get_response(self.controller)
self.assertEquals(resp.content_type, 'application/xml') self.assertEquals(resp.content_type, 'application/xml')
self.assertEquals(resp.body, xml_body) self.assertEquals(resp.body, xml_body)
self.assertEquals(resp.charset, 'utf-8') self.assertEquals(resp.charset, 'utf-8')
@@ -938,7 +939,7 @@ class TestContainerController(unittest.TestCase):
req = Request.blank('/sda1/p/a/xmlc', req = Request.blank('/sda1/p/a/xmlc',
environ={'REQUEST_METHOD': 'GET'}) environ={'REQUEST_METHOD': 'GET'})
req.accept = xml_accept req.accept = xml_accept
resp = self.controller.GET(req) resp = req.get_response(self.controller)
self.assertEquals(resp.body, xml_body, self.assertEquals(resp.body, xml_body,
'Invalid body for Accept: %s' % xml_accept) 'Invalid body for Accept: %s' % xml_accept)
self.assertEquals(resp.content_type, 'application/xml', self.assertEquals(resp.content_type, 'application/xml',
@@ -954,7 +955,7 @@ class TestContainerController(unittest.TestCase):
req = Request.blank('/sda1/p/a/xmlc', req = Request.blank('/sda1/p/a/xmlc',
environ={'REQUEST_METHOD': 'GET'}) environ={'REQUEST_METHOD': 'GET'})
req.accept = 'text/xml' req.accept = 'text/xml'
resp = self.controller.GET(req) resp = req.get_response(self.controller)
self.assertEquals(resp.content_type, 'text/xml') self.assertEquals(resp.content_type, 'text/xml')
self.assertEquals(resp.body, xml_body) self.assertEquals(resp.body, xml_body)
@@ -971,8 +972,9 @@ class TestContainerController(unittest.TestCase):
resp = req.get_response(self.controller) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 201) self.assertEquals(resp.status_int, 201)
# test limit with marker # test limit with marker
req = Request.blank('/sda1/p/a/c?limit=2&marker=1', environ={'REQUEST_METHOD': 'GET'}) req = Request.blank('/sda1/p/a/c?limit=2&marker=1',
resp = self.controller.GET(req) environ={'REQUEST_METHOD': 'GET'})
resp = req.get_response(self.controller)
result = resp.body.split() result = resp.body.split()
self.assertEquals(result, ['2', ]) self.assertEquals(result, ['2', ])
@@ -987,17 +989,18 @@ class TestContainerController(unittest.TestCase):
'REQUEST_METHOD': 'PUT', 'REQUEST_METHOD': 'PUT',
'HTTP_X_TIMESTAMP': '1', 'HTTP_X_CONTENT_TYPE': ctype, 'HTTP_X_TIMESTAMP': '1', 'HTTP_X_CONTENT_TYPE': ctype,
'HTTP_X_ETAG': 'x', 'HTTP_X_SIZE': 0}) 'HTTP_X_ETAG': 'x', 'HTTP_X_SIZE': 0})
resp = self.controller.PUT(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 201) self.assertEquals(resp.status_int, 201)
req = Request.blank('/sda1/p/a/c?format=json', environ={'REQUEST_METHOD': 'GET'}) req = Request.blank('/sda1/p/a/c?format=json',
resp = self.controller.GET(req) environ={'REQUEST_METHOD': 'GET'})
resp = req.get_response(self.controller)
result = [x['content_type'] for x in simplejson.loads(resp.body)] result = [x['content_type'] for x in simplejson.loads(resp.body)]
self.assertEquals(result, [u'\u2603', 'text/plain;charset="utf-8"']) self.assertEquals(result, [u'\u2603', 'text/plain;charset="utf-8"'])
def test_GET_accept_not_valid(self): def test_GET_accept_not_valid(self):
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT', req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT',
'HTTP_X_TIMESTAMP': '0'}) 'HTTP_X_TIMESTAMP': '0'})
self.controller.PUT(req) req.get_response(self.controller)
req = Request.blank('/sda1/p/a/c1', environ={'REQUEST_METHOD': 'PUT'}, req = Request.blank('/sda1/p/a/c1', environ={'REQUEST_METHOD': 'PUT'},
headers={'X-Put-Timestamp': '1', headers={'X-Put-Timestamp': '1',
'X-Delete-Timestamp': '0', 'X-Delete-Timestamp': '0',
@@ -1035,7 +1038,7 @@ class TestContainerController(unittest.TestCase):
def test_GET_prefix(self): def test_GET_prefix(self):
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT', req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT',
'HTTP_X_TIMESTAMP': '0'}) 'HTTP_X_TIMESTAMP': '0'})
resp = self.controller.PUT(req) resp = req.get_response(self.controller)
for i in ('a1', 'b1', 'a2', 'b2', 'a3', 'b3'): for i in ('a1', 'b1', 'a2', 'b2', 'a3', 'b3'):
req = Request.blank('/sda1/p/a/c/%s' % i, req = Request.blank('/sda1/p/a/c/%s' % i,
environ={ environ={
@@ -1060,7 +1063,7 @@ class TestContainerController(unittest.TestCase):
def test_GET_delimiter(self): def test_GET_delimiter(self):
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT', req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT',
'HTTP_X_TIMESTAMP': '0'}) 'HTTP_X_TIMESTAMP': '0'})
resp = self.controller.PUT(req) resp = req.get_response(self.controller)
for i in ('US-TX-A', 'US-TX-B', 'US-OK-A', 'US-OK-B', 'US-UT-A'): for i in ('US-TX-A', 'US-TX-B', 'US-OK-A', 'US-OK-B', 'US-UT-A'):
req = Request.blank('/sda1/p/a/c/%s' % i, req = Request.blank('/sda1/p/a/c/%s' % i,
environ={ environ={
@@ -1080,18 +1083,18 @@ class TestContainerController(unittest.TestCase):
def test_GET_delimiter_xml(self): def test_GET_delimiter_xml(self):
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT', req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT',
'HTTP_X_TIMESTAMP': '0'}) 'HTTP_X_TIMESTAMP': '0'})
resp = self.controller.PUT(req) resp = req.get_response(self.controller)
for i in ('US-TX-A', 'US-TX-B', 'US-OK-A', 'US-OK-B', 'US-UT-A'): for i in ('US-TX-A', 'US-TX-B', 'US-OK-A', 'US-OK-B', 'US-UT-A'):
req = Request.blank('/sda1/p/a/c/%s' % i, req = Request.blank('/sda1/p/a/c/%s' % i,
environ={ environ={
'REQUEST_METHOD': 'PUT', 'HTTP_X_TIMESTAMP': '1', 'REQUEST_METHOD': 'PUT', 'HTTP_X_TIMESTAMP': '1',
'HTTP_X_CONTENT_TYPE': 'text/plain', 'HTTP_X_ETAG': 'x', 'HTTP_X_CONTENT_TYPE': 'text/plain', 'HTTP_X_ETAG': 'x',
'HTTP_X_SIZE': 0}) 'HTTP_X_SIZE': 0})
resp = self.controller.PUT(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 201) self.assertEquals(resp.status_int, 201)
req = Request.blank('/sda1/p/a/c?prefix=US-&delimiter=-&format=xml', req = Request.blank('/sda1/p/a/c?prefix=US-&delimiter=-&format=xml',
environ={'REQUEST_METHOD': 'GET'}) environ={'REQUEST_METHOD': 'GET'})
resp = self.controller.GET(req) resp = req.get_response(self.controller)
self.assertEquals(resp.body, "<?xml version='1.0' encoding='UTF-8'?>" self.assertEquals(resp.body, "<?xml version='1.0' encoding='UTF-8'?>"
'\n<container name="c"><subdir name="US-OK-"><name>US-OK-</name></subdir>' '\n<container name="c"><subdir name="US-OK-"><name>US-OK-</name></subdir>'
'<subdir name="US-TX-"><name>US-TX-</name></subdir>' '<subdir name="US-TX-"><name>US-TX-</name></subdir>'
@@ -1100,17 +1103,17 @@ class TestContainerController(unittest.TestCase):
def test_GET_delimiter_xml_with_quotes(self): def test_GET_delimiter_xml_with_quotes(self):
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT', req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT',
'HTTP_X_TIMESTAMP': '0'}) 'HTTP_X_TIMESTAMP': '0'})
resp = self.controller.PUT(req) resp = req.get_response(self.controller)
req = Request.blank('/sda1/p/a/c/<\'sub\' "dir">/object', req = Request.blank('/sda1/p/a/c/<\'sub\' "dir">/object',
environ={ environ={
'REQUEST_METHOD': 'PUT', 'HTTP_X_TIMESTAMP': '1', 'REQUEST_METHOD': 'PUT', 'HTTP_X_TIMESTAMP': '1',
'HTTP_X_CONTENT_TYPE': 'text/plain', 'HTTP_X_ETAG': 'x', 'HTTP_X_CONTENT_TYPE': 'text/plain', 'HTTP_X_ETAG': 'x',
'HTTP_X_SIZE': 0}) 'HTTP_X_SIZE': 0})
resp = self.controller.PUT(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 201) self.assertEquals(resp.status_int, 201)
req = Request.blank('/sda1/p/a/c?delimiter=/&format=xml', req = Request.blank('/sda1/p/a/c?delimiter=/&format=xml',
environ={'REQUEST_METHOD': 'GET'}) environ={'REQUEST_METHOD': 'GET'})
resp = self.controller.GET(req) resp = req.get_response(self.controller)
dom = minidom.parseString(resp.body) dom = minidom.parseString(resp.body)
self.assert_(len(dom.getElementsByTagName('container')) == 1) self.assert_(len(dom.getElementsByTagName('container')) == 1)
container = dom.getElementsByTagName('container')[0] container = dom.getElementsByTagName('container')[0]
@@ -1126,18 +1129,18 @@ class TestContainerController(unittest.TestCase):
def test_GET_path(self): def test_GET_path(self):
req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT', req = Request.blank('/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT',
'HTTP_X_TIMESTAMP': '0'}) 'HTTP_X_TIMESTAMP': '0'})
resp = self.controller.PUT(req) resp = req.get_response(self.controller)
for i in ('US/TX', 'US/TX/B', 'US/OK', 'US/OK/B', 'US/UT/A'): for i in ('US/TX', 'US/TX/B', 'US/OK', 'US/OK/B', 'US/UT/A'):
req = Request.blank('/sda1/p/a/c/%s' % i, req = Request.blank('/sda1/p/a/c/%s' % i,
environ={ environ={
'REQUEST_METHOD': 'PUT', 'HTTP_X_TIMESTAMP': '1', 'REQUEST_METHOD': 'PUT', 'HTTP_X_TIMESTAMP': '1',
'HTTP_X_CONTENT_TYPE': 'text/plain', 'HTTP_X_ETAG': 'x', 'HTTP_X_CONTENT_TYPE': 'text/plain', 'HTTP_X_ETAG': 'x',
'HTTP_X_SIZE': 0}) 'HTTP_X_SIZE': 0})
resp = self.controller.PUT(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 201) self.assertEquals(resp.status_int, 201)
req = Request.blank('/sda1/p/a/c?path=US&format=json', req = Request.blank('/sda1/p/a/c?path=US&format=json',
environ={'REQUEST_METHOD': 'GET'}) environ={'REQUEST_METHOD': 'GET'})
resp = self.controller.GET(req) resp = req.get_response(self.controller)
self.assertEquals(simplejson.loads(resp.body), self.assertEquals(simplejson.loads(resp.body),
[{"name":"US/OK", "hash":"x", "bytes":0, "content_type":"text/plain", [{"name":"US/OK", "hash":"x", "bytes":0, "content_type":"text/plain",
"last_modified":"1970-01-01T00:00:01.000000Z"}, "last_modified":"1970-01-01T00:00:01.000000Z"},
@@ -1149,7 +1152,7 @@ class TestContainerController(unittest.TestCase):
{'devices': self.testdir}) {'devices': self.testdir})
req = Request.blank('/sda-null/p/a/c', environ={'REQUEST_METHOD': 'GET', req = Request.blank('/sda-null/p/a/c', environ={'REQUEST_METHOD': 'GET',
'HTTP_X_TIMESTAMP': '1'}) 'HTTP_X_TIMESTAMP': '1'})
resp = self.controller.GET(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 507) self.assertEquals(resp.status_int, 507)
def test_through_call(self): def test_through_call(self):
@@ -1257,13 +1260,14 @@ class TestContainerController(unittest.TestCase):
self.assertEquals(outbuf.getvalue()[:4], '405 ') self.assertEquals(outbuf.getvalue()[:4], '405 ')
def test_params_format(self): def test_params_format(self):
self.controller.PUT(Request.blank('/sda1/p/a/c', req = Request.blank('/sda1/p/a/c',
headers={'X-Timestamp': normalize_timestamp(1)}, headers={'X-Timestamp': normalize_timestamp(1)},
environ={'REQUEST_METHOD': 'PUT'})) environ={'REQUEST_METHOD': 'PUT'})
req.get_response(self.controller)
for format in ('xml', 'json'): for format in ('xml', 'json'):
req = Request.blank('/sda1/p/a/c?format=%s' % format, req = Request.blank('/sda1/p/a/c?format=%s' % format,
environ={'REQUEST_METHOD': 'GET'}) environ={'REQUEST_METHOD': 'GET'})
resp = self.controller.GET(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 200) self.assertEquals(resp.status_int, 200)
def test_params_utf8(self): def test_params_utf8(self):
@@ -1278,18 +1282,19 @@ class TestContainerController(unittest.TestCase):
# Good UTF8 sequence for delimiter, too long (1 byte delimiters only) # Good UTF8 sequence for delimiter, too long (1 byte delimiters only)
req = Request.blank('/sda1/p/a/c?delimiter=\xce\xa9', req = Request.blank('/sda1/p/a/c?delimiter=\xce\xa9',
environ={'REQUEST_METHOD': 'GET'}) environ={'REQUEST_METHOD': 'GET'})
resp = self.controller.GET(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 412, self.assertEquals(resp.status_int, 412,
"%d on param delimiter" % (resp.status_int)) "%d on param delimiter" % (resp.status_int))
self.controller.PUT(Request.blank('/sda1/p/a/c', req = Request.blank('/sda1/p/a/c',
headers={'X-Timestamp': normalize_timestamp(1)}, headers={'X-Timestamp': normalize_timestamp(1)},
environ={'REQUEST_METHOD': 'PUT'})) environ={'REQUEST_METHOD': 'PUT'})
req.get_response(self.controller)
# Good UTF8 sequence, ignored for limit, doesn't affect other queries # Good UTF8 sequence, ignored for limit, doesn't affect other queries
for param in ('limit', 'marker', 'path', 'prefix', 'end_marker', for param in ('limit', 'marker', 'path', 'prefix', 'end_marker',
'format'): 'format'):
req = Request.blank('/sda1/p/a/c?%s=\xce\xa9' % param, req = Request.blank('/sda1/p/a/c?%s=\xce\xa9' % param,
environ={'REQUEST_METHOD': 'GET'}) environ={'REQUEST_METHOD': 'GET'})
resp = self.controller.GET(req) resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 204, self.assertEquals(resp.status_int, 204,
"%d on param %s" % (resp.status_int, param)) "%d on param %s" % (resp.status_int, param))
@@ -1299,45 +1304,62 @@ class TestContainerController(unittest.TestCase):
'x-content-type': 'text/plain', 'x-content-type': 'text/plain',
'x-etag': 'd41d8cd98f00b204e9800998ecf8427e'} 'x-etag': 'd41d8cd98f00b204e9800998ecf8427e'}
resp = self.controller.PUT(Request.blank('/sda1/p/a/c/o', req = Request.blank('/sda1/p/a/c/o',
environ={'REQUEST_METHOD': 'PUT'}, headers=dict(headers))) environ={'REQUEST_METHOD': 'PUT'},
headers=dict(headers))
resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 404) self.assertEquals(resp.status_int, 404)
resp = self.controller.PUT(Request.blank('/sda1/p/.a/c/o', req = Request.blank('/sda1/p/.a/c/o',
environ={'REQUEST_METHOD': 'PUT'}, headers=dict(headers))) environ={'REQUEST_METHOD': 'PUT'},
headers=dict(headers))
resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 201) self.assertEquals(resp.status_int, 201)
resp = self.controller.PUT(Request.blank('/sda1/p/a/.c/o', req = Request.blank('/sda1/p/a/.c/o',
environ={'REQUEST_METHOD': 'PUT'}, headers=dict(headers))) environ={'REQUEST_METHOD': 'PUT'},
headers=dict(headers))
resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 404) self.assertEquals(resp.status_int, 404)
resp = self.controller.PUT(Request.blank('/sda1/p/a/.c/.o', req = Request.blank('/sda1/p/a/c/.o',
environ={'REQUEST_METHOD': 'PUT'}, headers=dict(headers))) environ={'REQUEST_METHOD': 'PUT'},
headers=dict(headers))
resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 404) self.assertEquals(resp.status_int, 404)
def test_delete_auto_create(self): def test_delete_auto_create(self):
headers = {'x-timestamp': normalize_timestamp(1)} headers = {'x-timestamp': normalize_timestamp(1)}
resp = self.controller.DELETE(Request.blank('/sda1/p/a/c/o', req = Request.blank('/sda1/p/a/c/o',
environ={'REQUEST_METHOD': 'DELETE'}, headers=dict(headers))) environ={'REQUEST_METHOD': 'DELETE'},
headers=dict(headers))
resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 404) self.assertEquals(resp.status_int, 404)
resp = self.controller.DELETE(Request.blank('/sda1/p/.a/c/o', req = Request.blank('/sda1/p/.a/c/o',
environ={'REQUEST_METHOD': 'DELETE'}, headers=dict(headers))) environ={'REQUEST_METHOD': 'DELETE'},
headers=dict(headers))
resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 204) self.assertEquals(resp.status_int, 204)
resp = self.controller.DELETE(Request.blank('/sda1/p/a/.c/o', req = Request.blank('/sda1/p/a/.c/o',
environ={'REQUEST_METHOD': 'DELETE'}, headers=dict(headers))) environ={'REQUEST_METHOD': 'DELETE'},
headers=dict(headers))
resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 404) self.assertEquals(resp.status_int, 404)
resp = self.controller.DELETE(Request.blank('/sda1/p/a/.c/.o', req = Request.blank('/sda1/p/a/.c/.o',
environ={'REQUEST_METHOD': 'DELETE'}, headers=dict(headers))) environ={'REQUEST_METHOD': 'DELETE'},
headers=dict(headers))
resp = req.get_response(self.controller)
self.assertEquals(resp.status_int, 404) self.assertEquals(resp.status_int, 404)
def test_content_type_on_HEAD(self): def test_content_type_on_HEAD(self):
self.controller.PUT(Request.blank('/sda1/p/a/o', Request.blank('/sda1/p/a/o',
headers={'X-Timestamp': normalize_timestamp(1)}, headers={'X-Timestamp': normalize_timestamp(1)},
environ={'REQUEST_METHOD': 'PUT'})) environ={'REQUEST_METHOD': 'PUT'}).get_response(
self.controller)
env = {'REQUEST_METHOD': 'HEAD'} env = {'REQUEST_METHOD': 'HEAD'}
@@ -1405,7 +1427,7 @@ class TestContainerController(unittest.TestCase):
orig_http_connect = container_server.http_connect orig_http_connect = container_server.http_connect
try: try:
container_server.http_connect = fake_http_connect container_server.http_connect = fake_http_connect
self.controller.PUT(req) req.get_response(self.controller)
finally: finally:
container_server.http_connect = orig_http_connect container_server.http_connect = orig_http_connect