2013-09-20 01:00:54 +08:00
|
|
|
# Copyright (c) 2010-2012 OpenStack Foundation
|
2010-07-12 17:03:45 -05:00
|
|
|
#
|
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
# you may not use this file except in compliance with the License.
|
|
|
|
# You may obtain a copy of the License at
|
|
|
|
#
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
#
|
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
|
|
# implied.
|
|
|
|
# See the License for the specific language governing permissions and
|
|
|
|
# limitations under the License.
|
|
|
|
|
|
|
|
import errno
|
|
|
|
import os
|
2012-12-17 06:39:25 -05:00
|
|
|
import mock
|
2018-02-05 14:06:18 -08:00
|
|
|
import posix
|
2010-07-12 17:03:45 -05:00
|
|
|
import unittest
|
2014-01-16 00:49:28 -05:00
|
|
|
from tempfile import mkdtemp
|
2010-07-12 17:03:45 -05:00
|
|
|
from shutil import rmtree
|
2014-02-17 10:31:20 +00:00
|
|
|
from test.unit import FakeLogger
|
2014-05-27 19:02:52 -07:00
|
|
|
import itertools
|
|
|
|
import random
|
2019-10-14 14:03:16 -07:00
|
|
|
from io import BytesIO
|
2010-07-12 17:03:45 -05:00
|
|
|
|
2015-10-30 11:02:54 -07:00
|
|
|
import json
|
2015-05-27 17:27:47 +02:00
|
|
|
from six import StringIO
|
2019-09-13 12:25:24 -05:00
|
|
|
from six.moves.urllib.parse import quote
|
2010-07-12 17:03:45 -05:00
|
|
|
import xml.dom.minidom
|
|
|
|
|
2015-01-28 22:29:22 +05:30
|
|
|
from swift import __version__ as swift_version
|
2015-11-06 01:49:58 +00:00
|
|
|
from swift.common.swob import (Request, WsgiBytesIO, HTTPNoContent)
|
2019-09-13 12:25:24 -05:00
|
|
|
from swift.common.constraints import ACCOUNT_LISTING_LIMIT
|
2019-07-24 16:59:08 -07:00
|
|
|
from swift.account.backend import AccountBroker
|
2014-04-02 16:16:21 -04:00
|
|
|
from swift.account.server import AccountController
|
2016-08-31 12:49:07 +00:00
|
|
|
from swift.common.utils import (normalize_timestamp, replication, public,
|
Support last modified on listing containers
For now, last modified timestamp is supported only on
object listing. (i.e. GET container)
For example:
GET container with json format results in like as:
[{"hash": "d41d8cd98f00b204e9800998ecf8427e", "last_modified":
"2015-06-10T04:58:23.460230", "bytes": 0, "name": "object",
"content_type": "application/octet-stream"}]
However, container listing (i.e. GET account) shows just a dict
consists of ("name", "bytes", "name") for each container.
For example:
GET accounts with json format result in like as:
[{"count": 0, "bytes": 0, "name": "container"}]
This patch is for supporting last_modified key in the container
listing results as well as object listing like as:
[{"count": 0, "bytes": 0, "name": "container", "last_modified":
"2015-06-10T04:58:23.460230"}]
This patch is changing just output for listing. The original
timestamp to show the last modified is already in container table
of account.db as a "put_timestamp" column.
Note that this patch *DOESN'T* change the put_timestamp semantics.
i.e. the last_modified timestamp will be changed only at both PUT
container and POST container.
(PUT object doesn't affect the timestamp)
Note that the tuple format of returning value from
swift.account.backend.AccountBroker.list_containers is now
(name, object_count, bytes_used, put_timestamp, 0)
* put_timestamp is added *
Original discussion was in working session at Vancouver Summit.
Etherpads are around here:
https://etherpad.openstack.org/p/liberty-swift-contributors-meetup
https://etherpad.openstack.org/p/liberty-container-listing-update
DocImpact
Change-Id: Iba0503916f1481a20c59ae9136436f40183e4c5b
2014-12-15 20:45:41 -08:00
|
|
|
mkdirs, storage_directory, Timestamp)
|
2019-09-13 12:25:24 -05:00
|
|
|
from swift.common.request_helpers import get_sys_meta_prefix, get_reserved_name
|
|
|
|
from test.unit import patch_policies, debug_logger, mock_check_drive, \
|
|
|
|
make_timestamp_iter
|
2014-06-23 12:52:50 -07:00
|
|
|
from swift.common.storage_policy import StoragePolicy, POLICIES
|
2010-07-12 17:03:45 -05:00
|
|
|
|
|
|
|
|
2014-05-27 19:02:52 -07:00
|
|
|
@patch_policies
|
2010-07-12 17:03:45 -05:00
|
|
|
class TestAccountController(unittest.TestCase):
|
2013-08-31 22:36:58 -04:00
|
|
|
"""Test swift.account.server.AccountController"""
|
2010-07-12 17:03:45 -05:00
|
|
|
def setUp(self):
|
2013-08-31 22:36:58 -04:00
|
|
|
"""Set up for testing swift.account.server.AccountController"""
|
2014-01-16 00:49:28 -05:00
|
|
|
self.testdir_base = mkdtemp()
|
|
|
|
self.testdir = os.path.join(self.testdir_base, 'account_server')
|
2017-04-19 15:09:40 +02:00
|
|
|
mkdirs(os.path.join(self.testdir, 'sda1'))
|
2019-12-31 13:48:13 -06:00
|
|
|
self.logger = debug_logger()
|
2010-07-12 17:03:45 -05:00
|
|
|
self.controller = AccountController(
|
2019-07-24 16:59:08 -07:00
|
|
|
{'devices': self.testdir, 'mount_check': 'false'},
|
2019-12-31 13:48:13 -06:00
|
|
|
logger=self.logger)
|
2019-09-13 12:25:24 -05:00
|
|
|
self.ts = make_timestamp_iter()
|
2010-07-12 17:03:45 -05:00
|
|
|
|
|
|
|
def tearDown(self):
|
2013-08-31 22:36:58 -04:00
|
|
|
"""Tear down for testing swift.account.server.AccountController"""
|
2010-07-12 17:03:45 -05:00
|
|
|
try:
|
2014-01-16 00:49:28 -05:00
|
|
|
rmtree(self.testdir_base)
|
2013-08-28 21:16:08 +02:00
|
|
|
except OSError as err:
|
2010-07-12 17:03:45 -05:00
|
|
|
if err.errno != errno.ENOENT:
|
|
|
|
raise
|
|
|
|
|
2019-12-31 13:48:13 -06:00
|
|
|
def test_init(self):
|
|
|
|
conf = {
|
|
|
|
'devices': self.testdir,
|
|
|
|
'mount_check': 'false',
|
|
|
|
}
|
|
|
|
AccountController(conf, logger=self.logger)
|
|
|
|
self.assertEqual(self.logger.get_lines_for_level('warning'), [])
|
|
|
|
conf['auto_create_account_prefix'] = '-'
|
|
|
|
AccountController(conf, logger=self.logger)
|
|
|
|
self.assertEqual(self.logger.get_lines_for_level('warning'), [
|
|
|
|
'Option auto_create_account_prefix is deprecated. '
|
|
|
|
'Configure auto_create_account_prefix under the '
|
|
|
|
'swift-constraints section of swift.conf. This option '
|
|
|
|
'will be ignored in a future release.'
|
|
|
|
])
|
|
|
|
|
2014-12-08 23:28:48 +05:30
|
|
|
def test_OPTIONS(self):
|
|
|
|
server_handler = AccountController(
|
|
|
|
{'devices': self.testdir, 'mount_check': 'false'})
|
|
|
|
req = Request.blank('/sda1/p/a/c/o', {'REQUEST_METHOD': 'OPTIONS'})
|
|
|
|
req.content_length = 0
|
|
|
|
resp = server_handler.OPTIONS(req)
|
2015-08-05 22:25:46 +05:30
|
|
|
self.assertEqual(200, resp.status_int)
|
2014-12-08 23:28:48 +05:30
|
|
|
for verb in 'OPTIONS GET POST PUT DELETE HEAD REPLICATE'.split():
|
2016-07-15 14:18:09 +02:00
|
|
|
self.assertIn(verb, resp.headers['Allow'].split(', '))
|
2015-08-05 22:25:46 +05:30
|
|
|
self.assertEqual(len(resp.headers['Allow'].split(', ')), 7)
|
|
|
|
self.assertEqual(resp.headers['Server'],
|
|
|
|
(server_handler.server_type + '/' + swift_version))
|
2014-12-08 23:28:48 +05:30
|
|
|
|
2017-04-19 15:09:40 +02:00
|
|
|
def test_insufficient_storage_mount_check_true(self):
|
|
|
|
conf = {'devices': self.testdir, 'mount_check': 'true'}
|
|
|
|
account_controller = AccountController(conf)
|
|
|
|
self.assertTrue(account_controller.mount_check)
|
|
|
|
for method in account_controller.allowed_methods:
|
|
|
|
if method == 'OPTIONS':
|
|
|
|
continue
|
|
|
|
req = Request.blank('/sda1/p/a-or-suff', method=method,
|
|
|
|
headers={'x-timestamp': '1'})
|
|
|
|
with mock_check_drive() as mocks:
|
|
|
|
try:
|
|
|
|
resp = req.get_response(account_controller)
|
|
|
|
self.assertEqual(resp.status_int, 507)
|
|
|
|
mocks['ismount'].return_value = True
|
|
|
|
resp = req.get_response(account_controller)
|
|
|
|
self.assertNotEqual(resp.status_int, 507)
|
|
|
|
# feel free to rip out this last assertion...
|
|
|
|
expected = 2 if method == 'PUT' else 4
|
|
|
|
self.assertEqual(resp.status_int // 100, expected)
|
|
|
|
except AssertionError as e:
|
|
|
|
self.fail('%s for %s' % (e, method))
|
|
|
|
|
|
|
|
def test_insufficient_storage_mount_check_false(self):
|
|
|
|
conf = {'devices': self.testdir, 'mount_check': 'false'}
|
|
|
|
account_controller = AccountController(conf)
|
|
|
|
self.assertFalse(account_controller.mount_check)
|
|
|
|
for method in account_controller.allowed_methods:
|
|
|
|
if method == 'OPTIONS':
|
|
|
|
continue
|
|
|
|
req = Request.blank('/sda1/p/a-or-suff', method=method,
|
|
|
|
headers={'x-timestamp': '1'})
|
|
|
|
with mock_check_drive() as mocks:
|
|
|
|
try:
|
|
|
|
resp = req.get_response(account_controller)
|
|
|
|
self.assertEqual(resp.status_int, 507)
|
|
|
|
mocks['isdir'].return_value = True
|
|
|
|
resp = req.get_response(account_controller)
|
|
|
|
self.assertNotEqual(resp.status_int, 507)
|
|
|
|
# feel free to rip out this last assertion...
|
|
|
|
expected = 2 if method == 'PUT' else 4
|
|
|
|
self.assertEqual(resp.status_int // 100, expected)
|
|
|
|
except AssertionError as e:
|
|
|
|
self.fail('%s for %s' % (e, method))
|
|
|
|
|
2010-07-12 17:03:45 -05:00
|
|
|
def test_DELETE_not_found(self):
|
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'DELETE',
|
2013-09-01 01:54:03 -04:00
|
|
|
'HTTP_X_TIMESTAMP': '0'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 404)
|
2016-12-12 15:18:52 +07:00
|
|
|
self.assertNotIn('X-Account-Status', resp.headers)
|
2010-07-12 17:03:45 -05:00
|
|
|
|
|
|
|
def test_DELETE_empty(self):
|
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'PUT',
|
2013-09-01 01:54:03 -04:00
|
|
|
'HTTP_X_TIMESTAMP': '0'})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'DELETE',
|
2013-09-01 01:54:03 -04:00
|
|
|
'HTTP_X_TIMESTAMP': '1'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 204)
|
|
|
|
self.assertEqual(resp.headers['X-Account-Status'], 'Deleted')
|
2010-07-12 17:03:45 -05:00
|
|
|
|
|
|
|
def test_DELETE_not_empty(self):
|
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'PUT',
|
2013-09-01 01:54:03 -04:00
|
|
|
'HTTP_X_TIMESTAMP': '0'})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a/c1', environ={'REQUEST_METHOD': 'PUT'},
|
|
|
|
headers={'X-Put-Timestamp': '1',
|
|
|
|
'X-Delete-Timestamp': '0',
|
|
|
|
'X-Object-Count': '0',
|
|
|
|
'X-Bytes-Used': '0'})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'DELETE',
|
2013-09-01 01:54:03 -04:00
|
|
|
'HTTP_X_TIMESTAMP': '1'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2010-07-12 17:03:45 -05:00
|
|
|
# We now allow deleting non-empty accounts
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 204)
|
|
|
|
self.assertEqual(resp.headers['X-Account-Status'], 'Deleted')
|
2010-07-12 17:03:45 -05:00
|
|
|
|
|
|
|
def test_DELETE_now_empty(self):
|
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'PUT',
|
2013-09-01 01:54:03 -04:00
|
|
|
'HTTP_X_TIMESTAMP': '0'})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a/c1', environ={'REQUEST_METHOD': 'PUT'},
|
|
|
|
headers={'X-Put-Timestamp': '1',
|
|
|
|
'X-Delete-Timestamp': '0',
|
|
|
|
'X-Object-Count': '0',
|
|
|
|
'X-Bytes-Used': '0',
|
|
|
|
'X-Timestamp': normalize_timestamp(0)})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2013-09-01 01:54:03 -04:00
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a/c1',
|
2010-07-12 17:03:45 -05:00
|
|
|
environ={'REQUEST_METHOD': 'PUT'},
|
|
|
|
headers={'X-Put-Timestamp': '1',
|
|
|
|
'X-Delete-Timestamp': '2',
|
|
|
|
'X-Object-Count': '0',
|
|
|
|
'X-Bytes-Used': '0',
|
|
|
|
'X-Timestamp': normalize_timestamp(0)})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 204)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'DELETE',
|
2013-09-01 01:54:03 -04:00
|
|
|
'HTTP_X_TIMESTAMP': '1'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 204)
|
|
|
|
self.assertEqual(resp.headers['X-Account-Status'], 'Deleted')
|
2010-07-12 17:03:45 -05:00
|
|
|
|
2013-03-18 18:01:16 -07:00
|
|
|
def test_DELETE_invalid_partition(self):
|
|
|
|
req = Request.blank('/sda1/./a', environ={'REQUEST_METHOD': 'DELETE',
|
|
|
|
'HTTP_X_TIMESTAMP': '1'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 400)
|
2013-03-18 18:01:16 -07:00
|
|
|
|
|
|
|
def test_DELETE_timestamp_not_float(self):
|
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'PUT',
|
|
|
|
'HTTP_X_TIMESTAMP': '0'})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2013-03-18 18:01:16 -07:00
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'DELETE'},
|
|
|
|
headers={'X-Timestamp': 'not-float'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 400)
|
2013-03-18 18:01:16 -07:00
|
|
|
|
2018-02-05 14:06:18 -08:00
|
|
|
def test_REPLICATE_insufficient_space(self):
|
|
|
|
conf = {'devices': self.testdir,
|
|
|
|
'mount_check': 'false',
|
|
|
|
'fallocate_reserve': '2%'}
|
|
|
|
account_controller = AccountController(conf)
|
|
|
|
|
|
|
|
req = Request.blank('/sda1/p/a',
|
|
|
|
environ={'REQUEST_METHOD': 'REPLICATE'})
|
|
|
|
statvfs_result = posix.statvfs_result([
|
|
|
|
4096, # f_bsize
|
|
|
|
4096, # f_frsize
|
|
|
|
2854907, # f_blocks
|
|
|
|
59000, # f_bfree
|
|
|
|
57000, # f_bavail (just under 2% free)
|
|
|
|
1280000, # f_files
|
|
|
|
1266040, # f_ffree,
|
|
|
|
1266040, # f_favail,
|
|
|
|
4096, # f_flag
|
|
|
|
255, # f_namemax
|
|
|
|
])
|
|
|
|
with mock.patch('os.statvfs',
|
|
|
|
return_value=statvfs_result) as mock_statvfs:
|
|
|
|
resp = req.get_response(account_controller)
|
|
|
|
self.assertEqual(resp.status_int, 507)
|
|
|
|
self.assertEqual(mock_statvfs.mock_calls,
|
|
|
|
[mock.call(os.path.join(self.testdir, 'sda1'))])
|
|
|
|
|
2016-08-03 17:11:25 +08:00
|
|
|
def test_REPLICATE_rsync_then_merge_works(self):
|
2015-11-06 01:49:58 +00:00
|
|
|
def fake_rsync_then_merge(self, drive, db_file, args):
|
|
|
|
return HTTPNoContent()
|
|
|
|
|
|
|
|
with mock.patch("swift.common.db_replicator.ReplicatorRpc."
|
|
|
|
"rsync_then_merge", fake_rsync_then_merge):
|
|
|
|
req = Request.blank('/sda1/p/a/',
|
|
|
|
environ={'REQUEST_METHOD': 'REPLICATE'},
|
|
|
|
headers={})
|
2018-10-23 00:57:50 -05:00
|
|
|
json_string = b'["rsync_then_merge", "a.db"]'
|
2015-11-06 01:49:58 +00:00
|
|
|
inbuf = WsgiBytesIO(json_string)
|
|
|
|
req.environ['wsgi.input'] = inbuf
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 204)
|
|
|
|
|
2016-08-03 17:11:25 +08:00
|
|
|
def test_REPLICATE_complete_rsync_works(self):
|
|
|
|
def fake_complete_rsync(self, drive, db_file, args):
|
|
|
|
return HTTPNoContent()
|
|
|
|
# check complete_rsync
|
|
|
|
with mock.patch("swift.common.db_replicator.ReplicatorRpc."
|
|
|
|
"complete_rsync", fake_complete_rsync):
|
|
|
|
req = Request.blank('/sda1/p/a/',
|
|
|
|
environ={'REQUEST_METHOD': 'REPLICATE'},
|
|
|
|
headers={})
|
2018-10-23 00:57:50 -05:00
|
|
|
json_string = b'["complete_rsync", "a.db"]'
|
2016-08-03 17:11:25 +08:00
|
|
|
inbuf = WsgiBytesIO(json_string)
|
|
|
|
req.environ['wsgi.input'] = inbuf
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 204)
|
|
|
|
|
|
|
|
def test_REPLICATE_value_error_works(self):
|
|
|
|
req = Request.blank('/sda1/p/a/',
|
|
|
|
environ={'REQUEST_METHOD': 'REPLICATE'},
|
|
|
|
headers={})
|
|
|
|
|
2015-11-06 01:49:58 +00:00
|
|
|
# check valuerror
|
2018-10-23 00:57:50 -05:00
|
|
|
wsgi_input_valuerror = b'["sync" : sync, "-1"]'
|
2015-11-06 01:49:58 +00:00
|
|
|
inbuf1 = WsgiBytesIO(wsgi_input_valuerror)
|
|
|
|
req.environ['wsgi.input'] = inbuf1
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 400)
|
|
|
|
|
2016-08-31 12:49:07 +00:00
|
|
|
def test_REPLICATE_unknown_sync(self):
|
|
|
|
# First without existing DB file
|
|
|
|
req = Request.blank('/sda1/p/a/',
|
|
|
|
environ={'REQUEST_METHOD': 'REPLICATE'},
|
|
|
|
headers={})
|
2018-10-23 00:57:50 -05:00
|
|
|
json_string = b'["unknown_sync", "a.db"]'
|
2016-08-31 12:49:07 +00:00
|
|
|
inbuf = WsgiBytesIO(json_string)
|
|
|
|
req.environ['wsgi.input'] = inbuf
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 404)
|
|
|
|
|
|
|
|
mkdirs(os.path.join(self.testdir, 'sda1', 'accounts', 'p', 'a', 'a'))
|
|
|
|
db_file = os.path.join(self.testdir, 'sda1',
|
|
|
|
storage_directory('accounts', 'p', 'a'),
|
|
|
|
'a' + '.db')
|
|
|
|
open(db_file, 'w')
|
|
|
|
req = Request.blank('/sda1/p/a/',
|
|
|
|
environ={'REQUEST_METHOD': 'REPLICATE'},
|
|
|
|
headers={})
|
2018-10-23 00:57:50 -05:00
|
|
|
json_string = b'["unknown_sync", "a.db"]'
|
2016-08-31 12:49:07 +00:00
|
|
|
inbuf = WsgiBytesIO(json_string)
|
|
|
|
req.environ['wsgi.input'] = inbuf
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 500)
|
|
|
|
|
2010-07-12 17:03:45 -05:00
|
|
|
def test_HEAD_not_found(self):
|
2013-06-26 08:23:00 +03:00
|
|
|
# Test the case in which account does not exist (can be recreated)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'HEAD'})
|
Refactor how we pick listings' content type.
There were a few different places where we had some repeated code to
figure out what format an account or container listing response should
be in (text, JSON, or XML). Now that's been pulled into a single
function.
As part of this, you can now raise HTTPException subclasses in proxy
controllers instead of laboriously plumbing error responses all the
way back up to swift.proxy.server.Application.handle_request(). This
lets us avoid certain ugly patterns, like the one where a method
returns a tuple of (x, y, z, error) and the caller has to see if it
got (value, value, value, None) or (None, None, None, errorvalue). Now
we can just raise the error.
Change-Id: I316873df289160d526487ad116f6fbb9a575e3de
2013-08-14 11:55:15 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 404)
|
2016-12-12 15:18:52 +07:00
|
|
|
self.assertNotIn('X-Account-Status', resp.headers)
|
2013-06-26 08:23:00 +03:00
|
|
|
|
|
|
|
# Test the case in which account was deleted but not yet reaped
|
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'PUT',
|
|
|
|
'HTTP_X_TIMESTAMP': '0'})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2013-06-26 08:23:00 +03:00
|
|
|
req = Request.blank('/sda1/p/a/c1', environ={'REQUEST_METHOD': 'PUT'},
|
|
|
|
headers={'X-Put-Timestamp': '1',
|
|
|
|
'X-Delete-Timestamp': '0',
|
|
|
|
'X-Object-Count': '0',
|
|
|
|
'X-Bytes-Used': '0'})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2013-06-26 08:23:00 +03:00
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'DELETE',
|
|
|
|
'HTTP_X_TIMESTAMP': '1'})
|
2013-07-24 12:55:25 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-06-26 08:23:00 +03:00
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'HEAD'})
|
2013-07-24 12:55:25 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 404)
|
|
|
|
self.assertEqual(resp.headers['X-Account-Status'], 'Deleted')
|
2010-07-12 17:03:45 -05:00
|
|
|
|
|
|
|
def test_HEAD_empty_account(self):
|
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'PUT',
|
2013-09-01 01:54:03 -04:00
|
|
|
'HTTP_X_TIMESTAMP': '0'})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'HEAD'})
|
Refactor how we pick listings' content type.
There were a few different places where we had some repeated code to
figure out what format an account or container listing response should
be in (text, JSON, or XML). Now that's been pulled into a single
function.
As part of this, you can now raise HTTPException subclasses in proxy
controllers instead of laboriously plumbing error responses all the
way back up to swift.proxy.server.Application.handle_request(). This
lets us avoid certain ugly patterns, like the one where a method
returns a tuple of (x, y, z, error) and the caller has to see if it
got (value, value, value, None) or (None, None, None, errorvalue). Now
we can just raise the error.
Change-Id: I316873df289160d526487ad116f6fbb9a575e3de
2013-08-14 11:55:15 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 204)
|
|
|
|
self.assertEqual(resp.headers['x-account-container-count'], '0')
|
|
|
|
self.assertEqual(resp.headers['x-account-object-count'], '0')
|
|
|
|
self.assertEqual(resp.headers['x-account-bytes-used'], '0')
|
2010-07-12 17:03:45 -05:00
|
|
|
|
|
|
|
def test_HEAD_with_containers(self):
|
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'PUT'},
|
|
|
|
headers={'X-Timestamp': '0'})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a/c1', environ={'REQUEST_METHOD': 'PUT'},
|
|
|
|
headers={'X-Put-Timestamp': '1',
|
|
|
|
'X-Delete-Timestamp': '0',
|
|
|
|
'X-Object-Count': '0',
|
|
|
|
'X-Bytes-Used': '0',
|
|
|
|
'X-Timestamp': normalize_timestamp(0)})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a/c2', environ={'REQUEST_METHOD': 'PUT'},
|
|
|
|
headers={'X-Put-Timestamp': '2',
|
|
|
|
'X-Delete-Timestamp': '0',
|
|
|
|
'X-Object-Count': '0',
|
|
|
|
'X-Bytes-Used': '0',
|
|
|
|
'X-Timestamp': normalize_timestamp(0)})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'HEAD'})
|
Refactor how we pick listings' content type.
There were a few different places where we had some repeated code to
figure out what format an account or container listing response should
be in (text, JSON, or XML). Now that's been pulled into a single
function.
As part of this, you can now raise HTTPException subclasses in proxy
controllers instead of laboriously plumbing error responses all the
way back up to swift.proxy.server.Application.handle_request(). This
lets us avoid certain ugly patterns, like the one where a method
returns a tuple of (x, y, z, error) and the caller has to see if it
got (value, value, value, None) or (None, None, None, errorvalue). Now
we can just raise the error.
Change-Id: I316873df289160d526487ad116f6fbb9a575e3de
2013-08-14 11:55:15 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 204)
|
|
|
|
self.assertEqual(resp.headers['x-account-container-count'], '2')
|
|
|
|
self.assertEqual(resp.headers['x-account-object-count'], '0')
|
|
|
|
self.assertEqual(resp.headers['x-account-bytes-used'], '0')
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a/c1', environ={'REQUEST_METHOD': 'PUT'},
|
|
|
|
headers={'X-Put-Timestamp': '1',
|
|
|
|
'X-Delete-Timestamp': '0',
|
|
|
|
'X-Object-Count': '1',
|
|
|
|
'X-Bytes-Used': '2',
|
|
|
|
'X-Timestamp': normalize_timestamp(0)})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a/c2', environ={'REQUEST_METHOD': 'PUT'},
|
|
|
|
headers={'X-Put-Timestamp': '2',
|
|
|
|
'X-Delete-Timestamp': '0',
|
|
|
|
'X-Object-Count': '3',
|
|
|
|
'X-Bytes-Used': '4',
|
|
|
|
'X-Timestamp': normalize_timestamp(0)})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'HEAD',
|
2013-09-01 01:54:03 -04:00
|
|
|
'HTTP_X_TIMESTAMP': '5'})
|
Refactor how we pick listings' content type.
There were a few different places where we had some repeated code to
figure out what format an account or container listing response should
be in (text, JSON, or XML). Now that's been pulled into a single
function.
As part of this, you can now raise HTTPException subclasses in proxy
controllers instead of laboriously plumbing error responses all the
way back up to swift.proxy.server.Application.handle_request(). This
lets us avoid certain ugly patterns, like the one where a method
returns a tuple of (x, y, z, error) and the caller has to see if it
got (value, value, value, None) or (None, None, None, errorvalue). Now
we can just raise the error.
Change-Id: I316873df289160d526487ad116f6fbb9a575e3de
2013-08-14 11:55:15 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 204)
|
|
|
|
self.assertEqual(resp.headers['x-account-container-count'], '2')
|
|
|
|
self.assertEqual(resp.headers['x-account-object-count'], '4')
|
|
|
|
self.assertEqual(resp.headers['x-account-bytes-used'], '6')
|
2010-07-12 17:03:45 -05:00
|
|
|
|
2013-03-18 18:01:16 -07:00
|
|
|
def test_HEAD_invalid_partition(self):
|
|
|
|
req = Request.blank('/sda1/./a', environ={'REQUEST_METHOD': 'HEAD',
|
|
|
|
'HTTP_X_TIMESTAMP': '1'})
|
Refactor how we pick listings' content type.
There were a few different places where we had some repeated code to
figure out what format an account or container listing response should
be in (text, JSON, or XML). Now that's been pulled into a single
function.
As part of this, you can now raise HTTPException subclasses in proxy
controllers instead of laboriously plumbing error responses all the
way back up to swift.proxy.server.Application.handle_request(). This
lets us avoid certain ugly patterns, like the one where a method
returns a tuple of (x, y, z, error) and the caller has to see if it
got (value, value, value, None) or (None, None, None, errorvalue). Now
we can just raise the error.
Change-Id: I316873df289160d526487ad116f6fbb9a575e3de
2013-08-14 11:55:15 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 400)
|
2013-03-18 18:01:16 -07:00
|
|
|
|
|
|
|
def test_HEAD_invalid_content_type(self):
|
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'HEAD'},
|
|
|
|
headers={'Accept': 'application/plain'})
|
Refactor how we pick listings' content type.
There were a few different places where we had some repeated code to
figure out what format an account or container listing response should
be in (text, JSON, or XML). Now that's been pulled into a single
function.
As part of this, you can now raise HTTPException subclasses in proxy
controllers instead of laboriously plumbing error responses all the
way back up to swift.proxy.server.Application.handle_request(). This
lets us avoid certain ugly patterns, like the one where a method
returns a tuple of (x, y, z, error) and the caller has to see if it
got (value, value, value, None) or (None, None, None, errorvalue). Now
we can just raise the error.
Change-Id: I316873df289160d526487ad116f6fbb9a575e3de
2013-08-14 11:55:15 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 406)
|
2013-03-18 18:01:16 -07:00
|
|
|
|
2017-09-11 22:08:12 +00:00
|
|
|
def test_HEAD_invalid_accept(self):
|
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'HEAD'},
|
|
|
|
headers={'Accept': 'application/plain;q=1;q=0.5'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 400)
|
2018-10-23 00:57:50 -05:00
|
|
|
self.assertEqual(resp.body, b'')
|
2017-09-11 22:08:12 +00:00
|
|
|
|
2013-06-12 15:50:13 -07:00
|
|
|
def test_HEAD_invalid_format(self):
|
|
|
|
format = '%D1%BD%8A9' # invalid UTF-8; should be %E1%BD%8A9 (E -> D)
|
|
|
|
req = Request.blank('/sda1/p/a?format=' + format,
|
|
|
|
environ={'REQUEST_METHOD': 'HEAD'})
|
2013-07-24 12:55:25 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 400)
|
2013-06-12 15:50:13 -07:00
|
|
|
|
2010-07-12 17:03:45 -05:00
|
|
|
def test_PUT_not_found(self):
|
2013-09-01 01:54:03 -04:00
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a/c', environ={'REQUEST_METHOD': 'PUT'},
|
2010-07-12 17:03:45 -05:00
|
|
|
headers={'X-PUT-Timestamp': normalize_timestamp(1),
|
|
|
|
'X-DELETE-Timestamp': normalize_timestamp(0),
|
|
|
|
'X-Object-Count': '1',
|
|
|
|
'X-Bytes-Used': '1',
|
|
|
|
'X-Timestamp': normalize_timestamp(0)})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 404)
|
2016-12-12 15:18:52 +07:00
|
|
|
self.assertNotIn('X-Account-Status', resp.headers)
|
2010-07-12 17:03:45 -05:00
|
|
|
|
2018-02-05 14:06:18 -08:00
|
|
|
def test_PUT_insufficient_space(self):
|
|
|
|
conf = {'devices': self.testdir,
|
|
|
|
'mount_check': 'false',
|
|
|
|
'fallocate_reserve': '2%'}
|
|
|
|
account_controller = AccountController(conf)
|
|
|
|
|
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a',
|
|
|
|
environ={'REQUEST_METHOD': 'PUT'},
|
|
|
|
headers={'X-Timestamp': '1517612949.541469'})
|
|
|
|
statvfs_result = posix.statvfs_result([
|
|
|
|
4096, # f_bsize
|
|
|
|
4096, # f_frsize
|
|
|
|
2854907, # f_blocks
|
|
|
|
59000, # f_bfree
|
|
|
|
57000, # f_bavail (just under 2% free)
|
|
|
|
1280000, # f_files
|
|
|
|
1266040, # f_ffree,
|
|
|
|
1266040, # f_favail,
|
|
|
|
4096, # f_flag
|
|
|
|
255, # f_namemax
|
|
|
|
])
|
|
|
|
with mock.patch('os.statvfs',
|
|
|
|
return_value=statvfs_result) as mock_statvfs:
|
|
|
|
resp = req.get_response(account_controller)
|
|
|
|
self.assertEqual(resp.status_int, 507)
|
|
|
|
self.assertEqual(mock_statvfs.mock_calls,
|
|
|
|
[mock.call(os.path.join(self.testdir, 'sda1'))])
|
|
|
|
|
2010-07-12 17:03:45 -05:00
|
|
|
def test_PUT(self):
|
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'PUT',
|
2013-09-01 01:54:03 -04:00
|
|
|
'HTTP_X_TIMESTAMP': '0'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 201)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'PUT',
|
2013-09-01 01:54:03 -04:00
|
|
|
'HTTP_X_TIMESTAMP': '1'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 202)
|
2010-07-12 17:03:45 -05:00
|
|
|
|
2013-10-24 12:23:39 -04:00
|
|
|
def test_PUT_simulated_create_race(self):
|
|
|
|
state = ['initial']
|
|
|
|
|
|
|
|
from swift.account.backend import AccountBroker as OrigAcBr
|
|
|
|
|
|
|
|
class InterceptedAcBr(OrigAcBr):
|
|
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
super(InterceptedAcBr, self).__init__(*args, **kwargs)
|
|
|
|
if state[0] == 'initial':
|
|
|
|
# Do nothing initially
|
|
|
|
pass
|
|
|
|
elif state[0] == 'race':
|
|
|
|
# Save the original db_file attribute value
|
|
|
|
self._saved_db_file = self.db_file
|
2018-05-01 15:12:05 +01:00
|
|
|
self._db_file += '.doesnotexist'
|
2013-10-24 12:23:39 -04:00
|
|
|
|
|
|
|
def initialize(self, *args, **kwargs):
|
|
|
|
if state[0] == 'initial':
|
|
|
|
# Do nothing initially
|
|
|
|
pass
|
|
|
|
elif state[0] == 'race':
|
|
|
|
# Restore the original db_file attribute to get the race
|
|
|
|
# behavior
|
2018-05-01 15:12:05 +01:00
|
|
|
self._db_file = self._saved_db_file
|
2013-10-24 12:23:39 -04:00
|
|
|
return super(InterceptedAcBr, self).initialize(*args, **kwargs)
|
|
|
|
|
|
|
|
with mock.patch("swift.account.server.AccountBroker", InterceptedAcBr):
|
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'PUT',
|
|
|
|
'HTTP_X_TIMESTAMP': '0'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 201)
|
|
|
|
state[0] = "race"
|
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'PUT',
|
|
|
|
'HTTP_X_TIMESTAMP': '1'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 202)
|
|
|
|
|
2010-07-12 17:03:45 -05:00
|
|
|
def test_PUT_after_DELETE(self):
|
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'PUT'},
|
|
|
|
headers={'X-Timestamp': normalize_timestamp(1)})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 201)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'DELETE'},
|
|
|
|
headers={'X-Timestamp': normalize_timestamp(1)})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 204)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'PUT'},
|
|
|
|
headers={'X-Timestamp': normalize_timestamp(2)})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 403)
|
2018-10-23 00:57:50 -05:00
|
|
|
self.assertEqual(resp.body, b'Recently deleted')
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.headers['X-Account-Status'], 'Deleted')
|
2010-07-12 17:03:45 -05:00
|
|
|
|
2019-09-13 12:25:24 -05:00
|
|
|
def test_create_reserved_namespace_account(self):
|
|
|
|
path = '/sda1/p/%s' % get_reserved_name('a')
|
|
|
|
req = Request.blank(path, method='PUT', headers={
|
|
|
|
'X-Timestamp': next(self.ts).internal})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status, '201 Created')
|
|
|
|
|
|
|
|
path = '/sda1/p/%s' % get_reserved_name('foo', 'bar')
|
|
|
|
req = Request.blank(path, method='PUT', headers={
|
|
|
|
'X-Timestamp': next(self.ts).internal})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status, '201 Created')
|
|
|
|
|
|
|
|
def test_create_invalid_reserved_namespace_account(self):
|
|
|
|
account_name = get_reserved_name('foo', 'bar')[1:]
|
|
|
|
path = '/sda1/p/%s' % account_name
|
|
|
|
req = Request.blank(path, method='PUT', headers={
|
|
|
|
'X-Timestamp': next(self.ts).internal})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status, '400 Bad Request')
|
|
|
|
|
|
|
|
def test_create_reserved_container_in_account(self):
|
|
|
|
# create account
|
|
|
|
path = '/sda1/p/a'
|
|
|
|
req = Request.blank(path, method='PUT', headers={
|
|
|
|
'X-Timestamp': next(self.ts).internal})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 201)
|
|
|
|
# put null container in it
|
|
|
|
path += '/%s' % get_reserved_name('c', 'stuff')
|
|
|
|
req = Request.blank(path, method='PUT', headers={
|
|
|
|
'X-Timestamp': next(self.ts).internal,
|
|
|
|
'X-Put-Timestamp': next(self.ts).internal,
|
|
|
|
'X-Delete-Timestamp': 0,
|
|
|
|
'X-Object-Count': 0,
|
|
|
|
'X-Bytes-Used': 0,
|
|
|
|
})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status, '201 Created')
|
|
|
|
|
|
|
|
def test_create_invalid_reserved_container_in_account(self):
|
|
|
|
# create account
|
|
|
|
path = '/sda1/p/a'
|
|
|
|
req = Request.blank(path, method='PUT', headers={
|
|
|
|
'X-Timestamp': next(self.ts).internal})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 201)
|
|
|
|
# put invalid container in it
|
|
|
|
path += '/%s' % get_reserved_name('c', 'stuff')[1:]
|
|
|
|
req = Request.blank(path, method='PUT', headers={
|
|
|
|
'X-Timestamp': next(self.ts).internal,
|
|
|
|
'X-Put-Timestamp': next(self.ts).internal,
|
|
|
|
'X-Delete-Timestamp': 0,
|
|
|
|
'X-Object-Count': 0,
|
|
|
|
'X-Bytes-Used': 0,
|
|
|
|
})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status, '400 Bad Request')
|
|
|
|
|
2016-02-28 01:18:07 +00:00
|
|
|
def test_PUT_non_utf8_metadata(self):
|
|
|
|
# Set metadata header
|
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a', environ={'REQUEST_METHOD': 'PUT'},
|
|
|
|
headers={'X-Timestamp': normalize_timestamp(1),
|
|
|
|
'X-Account-Meta-Test': b'\xff'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 400)
|
|
|
|
# Set sysmeta header
|
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a', environ={'REQUEST_METHOD': 'PUT'},
|
|
|
|
headers={'X-Timestamp': normalize_timestamp(1),
|
|
|
|
'X-Account-Sysmeta-Access-Control': b'\xff'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 400)
|
|
|
|
# Send other
|
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a', environ={'REQUEST_METHOD': 'PUT'},
|
|
|
|
headers={'X-Timestamp': normalize_timestamp(1),
|
|
|
|
'X-Will-Not-Be-Saved': b'\xff'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 202)
|
|
|
|
|
2019-07-24 16:59:08 -07:00
|
|
|
def test_utf8_metadata(self):
|
|
|
|
ts_str = normalize_timestamp(1)
|
|
|
|
|
|
|
|
def get_test_meta(method, headers):
|
|
|
|
# Set metadata header
|
|
|
|
headers.setdefault('X-Timestamp', ts_str)
|
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a', environ={'REQUEST_METHOD': method},
|
|
|
|
headers=headers)
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertIn(resp.status_int, (201, 202, 204))
|
|
|
|
db_path = os.path.join(*next(
|
|
|
|
(dir_name, file_name)
|
|
|
|
for dir_name, _, files in os.walk(self.testdir)
|
|
|
|
for file_name in files if file_name.endswith('.db')
|
|
|
|
))
|
|
|
|
broker = AccountBroker(db_path)
|
|
|
|
# Why not use broker.metadata, you ask? Because we want to get
|
|
|
|
# as close to the on-disk format as is reasonable.
|
|
|
|
result = json.loads(broker.get_raw_metadata())
|
|
|
|
# Clear it out for the next run
|
|
|
|
with broker.get() as conn:
|
|
|
|
conn.execute("UPDATE account_stat SET metadata=''")
|
|
|
|
conn.commit()
|
|
|
|
return result
|
|
|
|
|
|
|
|
wsgi_str = '\xf0\x9f\x91\x8d'
|
|
|
|
uni_str = u'\U0001f44d'
|
|
|
|
|
|
|
|
self.assertEqual(
|
|
|
|
get_test_meta('PUT', {'x-account-sysmeta-' + wsgi_str: wsgi_str}),
|
|
|
|
{u'X-Account-Sysmeta-' + uni_str: [uni_str, ts_str]})
|
|
|
|
|
|
|
|
self.assertEqual(
|
|
|
|
get_test_meta('PUT', {'x-account-meta-' + wsgi_str: wsgi_str}),
|
|
|
|
{u'X-Account-Meta-' + uni_str: [uni_str, ts_str]})
|
|
|
|
|
|
|
|
self.assertEqual(
|
|
|
|
get_test_meta('POST', {'x-account-sysmeta-' + wsgi_str: wsgi_str}),
|
|
|
|
{u'X-Account-Sysmeta-' + uni_str: [uni_str, ts_str]})
|
|
|
|
|
|
|
|
self.assertEqual(
|
|
|
|
get_test_meta('POST', {'x-account-meta-' + wsgi_str: wsgi_str}),
|
|
|
|
{u'X-Account-Meta-' + uni_str: [uni_str, ts_str]})
|
|
|
|
|
2010-08-10 12:18:15 -07:00
|
|
|
def test_PUT_GET_metadata(self):
|
|
|
|
# Set metadata header
|
2013-09-01 01:54:03 -04:00
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a', environ={'REQUEST_METHOD': 'PUT'},
|
2010-08-10 12:18:15 -07:00
|
|
|
headers={'X-Timestamp': normalize_timestamp(1),
|
|
|
|
'X-Account-Meta-Test': 'Value'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 201)
|
2013-08-16 16:24:00 -07:00
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'GET'})
|
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 204)
|
|
|
|
self.assertEqual(resp.headers.get('x-account-meta-test'), 'Value')
|
2010-08-16 15:30:27 -07:00
|
|
|
# Set another metadata header, ensuring old one doesn't disappear
|
2013-09-01 01:54:03 -04:00
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a', environ={'REQUEST_METHOD': 'POST'},
|
2010-08-16 15:30:27 -07:00
|
|
|
headers={'X-Timestamp': normalize_timestamp(1),
|
|
|
|
'X-Account-Meta-Test2': 'Value2'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 204)
|
2013-08-16 16:24:00 -07:00
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'GET'})
|
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 204)
|
|
|
|
self.assertEqual(resp.headers.get('x-account-meta-test'), 'Value')
|
|
|
|
self.assertEqual(resp.headers.get('x-account-meta-test2'), 'Value2')
|
2010-08-10 12:18:15 -07:00
|
|
|
# Update metadata header
|
2013-09-01 01:54:03 -04:00
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a', environ={'REQUEST_METHOD': 'PUT'},
|
2010-08-10 12:18:15 -07:00
|
|
|
headers={'X-Timestamp': normalize_timestamp(3),
|
|
|
|
'X-Account-Meta-Test': 'New Value'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 202)
|
2013-08-16 16:24:00 -07:00
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'GET'})
|
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 204)
|
|
|
|
self.assertEqual(resp.headers.get('x-account-meta-test'), 'New Value')
|
2010-08-10 12:18:15 -07:00
|
|
|
# Send old update to metadata header
|
2013-09-01 01:54:03 -04:00
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a', environ={'REQUEST_METHOD': 'PUT'},
|
2010-08-10 12:18:15 -07:00
|
|
|
headers={'X-Timestamp': normalize_timestamp(2),
|
|
|
|
'X-Account-Meta-Test': 'Old Value'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 202)
|
2013-08-16 16:24:00 -07:00
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'GET'})
|
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 204)
|
|
|
|
self.assertEqual(resp.headers.get('x-account-meta-test'), 'New Value')
|
2010-08-10 12:18:15 -07:00
|
|
|
# Remove metadata header (by setting it to empty)
|
2013-09-01 01:54:03 -04:00
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a', environ={'REQUEST_METHOD': 'PUT'},
|
2010-08-10 12:18:15 -07:00
|
|
|
headers={'X-Timestamp': normalize_timestamp(4),
|
|
|
|
'X-Account-Meta-Test': ''})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 202)
|
2013-08-16 16:24:00 -07:00
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'GET'})
|
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 204)
|
2016-12-12 15:18:52 +07:00
|
|
|
self.assertNotIn('x-account-meta-test', resp.headers)
|
2010-08-10 12:18:15 -07:00
|
|
|
|
2013-12-03 22:02:39 +00:00
|
|
|
def test_PUT_GET_sys_metadata(self):
|
|
|
|
prefix = get_sys_meta_prefix('account')
|
|
|
|
hdr = '%stest' % prefix
|
|
|
|
hdr2 = '%stest2' % prefix
|
|
|
|
# Set metadata header
|
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a', environ={'REQUEST_METHOD': 'PUT'},
|
|
|
|
headers={'X-Timestamp': normalize_timestamp(1),
|
|
|
|
hdr.title(): 'Value'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 201)
|
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'GET'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 204)
|
|
|
|
self.assertEqual(resp.headers.get(hdr), 'Value')
|
|
|
|
# Set another metadata header, ensuring old one doesn't disappear
|
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a', environ={'REQUEST_METHOD': 'POST'},
|
|
|
|
headers={'X-Timestamp': normalize_timestamp(1),
|
|
|
|
hdr2.title(): 'Value2'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 204)
|
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'GET'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 204)
|
|
|
|
self.assertEqual(resp.headers.get(hdr), 'Value')
|
|
|
|
self.assertEqual(resp.headers.get(hdr2), 'Value2')
|
|
|
|
# Update metadata header
|
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a', environ={'REQUEST_METHOD': 'PUT'},
|
|
|
|
headers={'X-Timestamp': normalize_timestamp(3),
|
|
|
|
hdr.title(): 'New Value'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 202)
|
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'GET'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 204)
|
|
|
|
self.assertEqual(resp.headers.get(hdr), 'New Value')
|
|
|
|
# Send old update to metadata header
|
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a', environ={'REQUEST_METHOD': 'PUT'},
|
|
|
|
headers={'X-Timestamp': normalize_timestamp(2),
|
|
|
|
hdr.title(): 'Old Value'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 202)
|
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'GET'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 204)
|
|
|
|
self.assertEqual(resp.headers.get(hdr), 'New Value')
|
|
|
|
# Remove metadata header (by setting it to empty)
|
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a', environ={'REQUEST_METHOD': 'PUT'},
|
|
|
|
headers={'X-Timestamp': normalize_timestamp(4),
|
|
|
|
hdr.title(): ''})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 202)
|
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'GET'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 204)
|
2016-12-12 15:18:52 +07:00
|
|
|
self.assertNotIn(hdr, resp.headers)
|
2013-12-03 22:02:39 +00:00
|
|
|
|
2013-03-18 18:01:16 -07:00
|
|
|
def test_PUT_invalid_partition(self):
|
|
|
|
req = Request.blank('/sda1/./a', environ={'REQUEST_METHOD': 'PUT',
|
|
|
|
'HTTP_X_TIMESTAMP': '1'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 400)
|
2013-03-18 18:01:16 -07:00
|
|
|
|
2010-08-10 12:18:15 -07:00
|
|
|
def test_POST_HEAD_metadata(self):
|
2013-09-01 01:54:03 -04:00
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a', environ={'REQUEST_METHOD': 'PUT'},
|
2010-08-10 12:18:15 -07:00
|
|
|
headers={'X-Timestamp': normalize_timestamp(1)})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 201)
|
2010-08-10 12:18:15 -07:00
|
|
|
# Set metadata header
|
2013-09-01 01:54:03 -04:00
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a', environ={'REQUEST_METHOD': 'POST'},
|
2010-08-10 12:18:15 -07:00
|
|
|
headers={'X-Timestamp': normalize_timestamp(1),
|
|
|
|
'X-Account-Meta-Test': 'Value'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2019-09-13 12:25:24 -05:00
|
|
|
self.assertEqual(resp.status_int, 204, resp.body)
|
2010-08-10 12:18:15 -07:00
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'HEAD'})
|
Refactor how we pick listings' content type.
There were a few different places where we had some repeated code to
figure out what format an account or container listing response should
be in (text, JSON, or XML). Now that's been pulled into a single
function.
As part of this, you can now raise HTTPException subclasses in proxy
controllers instead of laboriously plumbing error responses all the
way back up to swift.proxy.server.Application.handle_request(). This
lets us avoid certain ugly patterns, like the one where a method
returns a tuple of (x, y, z, error) and the caller has to see if it
got (value, value, value, None) or (None, None, None, errorvalue). Now
we can just raise the error.
Change-Id: I316873df289160d526487ad116f6fbb9a575e3de
2013-08-14 11:55:15 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 204)
|
|
|
|
self.assertEqual(resp.headers.get('x-account-meta-test'), 'Value')
|
2010-08-10 12:18:15 -07:00
|
|
|
# Update metadata header
|
2013-09-01 01:54:03 -04:00
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a', environ={'REQUEST_METHOD': 'POST'},
|
2010-08-10 12:18:15 -07:00
|
|
|
headers={'X-Timestamp': normalize_timestamp(3),
|
|
|
|
'X-Account-Meta-Test': 'New Value'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 204)
|
2010-08-10 12:18:15 -07:00
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'HEAD'})
|
Refactor how we pick listings' content type.
There were a few different places where we had some repeated code to
figure out what format an account or container listing response should
be in (text, JSON, or XML). Now that's been pulled into a single
function.
As part of this, you can now raise HTTPException subclasses in proxy
controllers instead of laboriously plumbing error responses all the
way back up to swift.proxy.server.Application.handle_request(). This
lets us avoid certain ugly patterns, like the one where a method
returns a tuple of (x, y, z, error) and the caller has to see if it
got (value, value, value, None) or (None, None, None, errorvalue). Now
we can just raise the error.
Change-Id: I316873df289160d526487ad116f6fbb9a575e3de
2013-08-14 11:55:15 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 204)
|
|
|
|
self.assertEqual(resp.headers.get('x-account-meta-test'), 'New Value')
|
2010-08-10 12:18:15 -07:00
|
|
|
# Send old update to metadata header
|
2013-09-01 01:54:03 -04:00
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a', environ={'REQUEST_METHOD': 'POST'},
|
2010-08-10 12:18:15 -07:00
|
|
|
headers={'X-Timestamp': normalize_timestamp(2),
|
|
|
|
'X-Account-Meta-Test': 'Old Value'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 204)
|
2010-08-10 12:18:15 -07:00
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'HEAD'})
|
Refactor how we pick listings' content type.
There were a few different places where we had some repeated code to
figure out what format an account or container listing response should
be in (text, JSON, or XML). Now that's been pulled into a single
function.
As part of this, you can now raise HTTPException subclasses in proxy
controllers instead of laboriously plumbing error responses all the
way back up to swift.proxy.server.Application.handle_request(). This
lets us avoid certain ugly patterns, like the one where a method
returns a tuple of (x, y, z, error) and the caller has to see if it
got (value, value, value, None) or (None, None, None, errorvalue). Now
we can just raise the error.
Change-Id: I316873df289160d526487ad116f6fbb9a575e3de
2013-08-14 11:55:15 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 204)
|
|
|
|
self.assertEqual(resp.headers.get('x-account-meta-test'), 'New Value')
|
2010-08-10 12:18:15 -07:00
|
|
|
# Remove metadata header (by setting it to empty)
|
2013-09-01 01:54:03 -04:00
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a', environ={'REQUEST_METHOD': 'POST'},
|
2010-08-10 12:18:15 -07:00
|
|
|
headers={'X-Timestamp': normalize_timestamp(4),
|
|
|
|
'X-Account-Meta-Test': ''})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 204)
|
2010-08-10 12:18:15 -07:00
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'HEAD'})
|
Refactor how we pick listings' content type.
There were a few different places where we had some repeated code to
figure out what format an account or container listing response should
be in (text, JSON, or XML). Now that's been pulled into a single
function.
As part of this, you can now raise HTTPException subclasses in proxy
controllers instead of laboriously plumbing error responses all the
way back up to swift.proxy.server.Application.handle_request(). This
lets us avoid certain ugly patterns, like the one where a method
returns a tuple of (x, y, z, error) and the caller has to see if it
got (value, value, value, None) or (None, None, None, errorvalue). Now
we can just raise the error.
Change-Id: I316873df289160d526487ad116f6fbb9a575e3de
2013-08-14 11:55:15 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 204)
|
2016-12-12 15:18:52 +07:00
|
|
|
self.assertNotIn('x-account-meta-test', resp.headers)
|
2010-08-10 12:18:15 -07:00
|
|
|
|
2013-12-03 22:02:39 +00:00
|
|
|
def test_POST_HEAD_sys_metadata(self):
|
|
|
|
prefix = get_sys_meta_prefix('account')
|
|
|
|
hdr = '%stest' % prefix
|
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a', environ={'REQUEST_METHOD': 'PUT'},
|
|
|
|
headers={'X-Timestamp': normalize_timestamp(1)})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 201)
|
|
|
|
# Set metadata header
|
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a', environ={'REQUEST_METHOD': 'POST'},
|
|
|
|
headers={'X-Timestamp': normalize_timestamp(1),
|
|
|
|
hdr.title(): 'Value'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 204)
|
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'HEAD'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 204)
|
|
|
|
self.assertEqual(resp.headers.get(hdr), 'Value')
|
|
|
|
# Update metadata header
|
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a', environ={'REQUEST_METHOD': 'POST'},
|
|
|
|
headers={'X-Timestamp': normalize_timestamp(3),
|
|
|
|
hdr.title(): 'New Value'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 204)
|
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'HEAD'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 204)
|
|
|
|
self.assertEqual(resp.headers.get(hdr), 'New Value')
|
|
|
|
# Send old update to metadata header
|
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a', environ={'REQUEST_METHOD': 'POST'},
|
|
|
|
headers={'X-Timestamp': normalize_timestamp(2),
|
|
|
|
hdr.title(): 'Old Value'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 204)
|
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'HEAD'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 204)
|
|
|
|
self.assertEqual(resp.headers.get(hdr), 'New Value')
|
|
|
|
# Remove metadata header (by setting it to empty)
|
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a', environ={'REQUEST_METHOD': 'POST'},
|
|
|
|
headers={'X-Timestamp': normalize_timestamp(4),
|
|
|
|
hdr.title(): ''})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 204)
|
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'HEAD'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 204)
|
2016-12-12 15:18:52 +07:00
|
|
|
self.assertNotIn(hdr, resp.headers)
|
2013-12-03 22:02:39 +00:00
|
|
|
|
2013-03-18 18:01:16 -07:00
|
|
|
def test_POST_invalid_partition(self):
|
|
|
|
req = Request.blank('/sda1/./a', environ={'REQUEST_METHOD': 'POST',
|
|
|
|
'HTTP_X_TIMESTAMP': '1'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 400)
|
2013-03-18 18:01:16 -07:00
|
|
|
|
2018-02-05 14:06:18 -08:00
|
|
|
def test_POST_insufficient_space(self):
|
|
|
|
conf = {'devices': self.testdir,
|
|
|
|
'mount_check': 'false',
|
|
|
|
'fallocate_reserve': '2%'}
|
|
|
|
account_controller = AccountController(conf)
|
|
|
|
|
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a',
|
|
|
|
environ={'REQUEST_METHOD': 'POST'},
|
|
|
|
headers={'X-Timestamp': '1517611584.937603'})
|
|
|
|
statvfs_result = posix.statvfs_result([
|
|
|
|
4096, # f_bsize
|
|
|
|
4096, # f_frsize
|
|
|
|
2854907, # f_blocks
|
|
|
|
59000, # f_bfree
|
|
|
|
57000, # f_bavail (just under 2% free)
|
|
|
|
1280000, # f_files
|
|
|
|
1266040, # f_ffree,
|
|
|
|
1266040, # f_favail,
|
|
|
|
4096, # f_flag
|
|
|
|
255, # f_namemax
|
|
|
|
])
|
|
|
|
with mock.patch('os.statvfs',
|
|
|
|
return_value=statvfs_result) as mock_statvfs:
|
|
|
|
resp = req.get_response(account_controller)
|
|
|
|
self.assertEqual(resp.status_int, 507)
|
|
|
|
self.assertEqual(mock_statvfs.mock_calls,
|
|
|
|
[mock.call(os.path.join(self.testdir, 'sda1'))])
|
|
|
|
|
2013-03-18 18:01:16 -07:00
|
|
|
def test_POST_timestamp_not_float(self):
|
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'POST',
|
|
|
|
'HTTP_X_TIMESTAMP': '0'},
|
|
|
|
headers={'X-Timestamp': 'not-float'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 400)
|
2013-03-18 18:01:16 -07:00
|
|
|
|
|
|
|
def test_POST_after_DELETE_not_found(self):
|
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'PUT',
|
|
|
|
'HTTP_X_TIMESTAMP': '0'})
|
2013-10-29 16:10:47 -06:00
|
|
|
resp = req.get_response(self.controller)
|
2015-08-05 22:25:46 +05:30
|
|
|
self.assertEqual(resp.status_int, 201)
|
2013-03-18 18:01:16 -07:00
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'DELETE',
|
|
|
|
'HTTP_X_TIMESTAMP': '1'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2015-08-05 22:25:46 +05:30
|
|
|
self.assertEqual(resp.status_int, 204)
|
2013-03-18 18:01:16 -07:00
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'POST',
|
|
|
|
'HTTP_X_TIMESTAMP': '2'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 404)
|
|
|
|
self.assertEqual(resp.headers['X-Account-Status'], 'Deleted')
|
2013-03-18 18:01:16 -07:00
|
|
|
|
2010-07-12 17:03:45 -05:00
|
|
|
def test_GET_not_found_plain(self):
|
2013-06-26 08:23:00 +03:00
|
|
|
# Test the case in which account does not exist (can be recreated)
|
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'GET'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 404)
|
2016-12-12 15:18:52 +07:00
|
|
|
self.assertNotIn('X-Account-Status', resp.headers)
|
2013-06-26 08:23:00 +03:00
|
|
|
|
|
|
|
# Test the case in which account was deleted but not yet reaped
|
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'PUT',
|
|
|
|
'HTTP_X_TIMESTAMP': '0'})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2013-06-26 08:23:00 +03:00
|
|
|
req = Request.blank('/sda1/p/a/c1', environ={'REQUEST_METHOD': 'PUT'},
|
|
|
|
headers={'X-Put-Timestamp': '1',
|
|
|
|
'X-Delete-Timestamp': '0',
|
|
|
|
'X-Object-Count': '0',
|
|
|
|
'X-Bytes-Used': '0'})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2013-06-26 08:23:00 +03:00
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'DELETE',
|
|
|
|
'HTTP_X_TIMESTAMP': '1'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'GET'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 404)
|
|
|
|
self.assertEqual(resp.headers['X-Account-Status'], 'Deleted')
|
2010-07-12 17:03:45 -05:00
|
|
|
|
|
|
|
def test_GET_not_found_json(self):
|
|
|
|
req = Request.blank('/sda1/p/a?format=json',
|
|
|
|
environ={'REQUEST_METHOD': 'GET'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 404)
|
2010-07-12 17:03:45 -05:00
|
|
|
|
|
|
|
def test_GET_not_found_xml(self):
|
|
|
|
req = Request.blank('/sda1/p/a?format=xml',
|
|
|
|
environ={'REQUEST_METHOD': 'GET'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 404)
|
2010-07-12 17:03:45 -05:00
|
|
|
|
|
|
|
def test_GET_empty_account_plain(self):
|
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'PUT',
|
2013-09-01 01:54:03 -04:00
|
|
|
'HTTP_X_TIMESTAMP': '0'})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'GET'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 204)
|
|
|
|
self.assertEqual(resp.headers['Content-Type'],
|
|
|
|
'text/plain; charset=utf-8')
|
2010-07-12 17:03:45 -05:00
|
|
|
|
|
|
|
def test_GET_empty_account_json(self):
|
|
|
|
req = Request.blank('/sda1/p/a?format=json',
|
2013-09-01 01:54:03 -04:00
|
|
|
environ={'REQUEST_METHOD': 'PUT',
|
|
|
|
'HTTP_X_TIMESTAMP': '0'})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a?format=json',
|
|
|
|
environ={'REQUEST_METHOD': 'GET'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 200)
|
|
|
|
self.assertEqual(resp.headers['Content-Type'],
|
|
|
|
'application/json; charset=utf-8')
|
2010-07-12 17:03:45 -05:00
|
|
|
|
|
|
|
def test_GET_empty_account_xml(self):
|
|
|
|
req = Request.blank('/sda1/p/a?format=xml',
|
2013-09-01 01:54:03 -04:00
|
|
|
environ={'REQUEST_METHOD': 'PUT',
|
|
|
|
'HTTP_X_TIMESTAMP': '0'})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a?format=xml',
|
|
|
|
environ={'REQUEST_METHOD': 'GET'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 200)
|
|
|
|
self.assertEqual(resp.headers['Content-Type'],
|
|
|
|
'application/xml; charset=utf-8')
|
2010-07-12 17:03:45 -05:00
|
|
|
|
2017-09-11 22:08:12 +00:00
|
|
|
def test_GET_invalid_accept(self):
|
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'GET'},
|
|
|
|
headers={'Accept': 'application/plain;q=foo'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 400)
|
2018-10-23 00:57:50 -05:00
|
|
|
self.assertEqual(resp.body, b'Invalid Accept header')
|
2017-09-11 22:08:12 +00:00
|
|
|
|
2010-07-12 17:03:45 -05:00
|
|
|
def test_GET_over_limit(self):
|
2013-09-01 01:54:03 -04:00
|
|
|
req = Request.blank(
|
2019-09-13 12:25:24 -05:00
|
|
|
'/sda1/p/a?limit=%d' % (ACCOUNT_LISTING_LIMIT + 1),
|
2013-09-01 01:54:03 -04:00
|
|
|
environ={'REQUEST_METHOD': 'GET'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 412)
|
2010-07-12 17:03:45 -05:00
|
|
|
|
|
|
|
def test_GET_with_containers_plain(self):
|
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'PUT',
|
2013-09-01 01:54:03 -04:00
|
|
|
'HTTP_X_TIMESTAMP': '0'})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a/c1', environ={'REQUEST_METHOD': 'PUT'},
|
|
|
|
headers={'X-Put-Timestamp': '1',
|
|
|
|
'X-Delete-Timestamp': '0',
|
|
|
|
'X-Object-Count': '0',
|
|
|
|
'X-Bytes-Used': '0',
|
|
|
|
'X-Timestamp': normalize_timestamp(0)})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a/c2', environ={'REQUEST_METHOD': 'PUT'},
|
|
|
|
headers={'X-Put-Timestamp': '2',
|
|
|
|
'X-Delete-Timestamp': '0',
|
|
|
|
'X-Object-Count': '0',
|
|
|
|
'X-Bytes-Used': '0',
|
|
|
|
'X-Timestamp': normalize_timestamp(0)})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'GET'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 200)
|
2018-12-27 23:01:52 +00:00
|
|
|
self.assertEqual(resp.body.strip().split(b'\n'),
|
|
|
|
[b'c1', b'c2'])
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a/c1', environ={'REQUEST_METHOD': 'PUT'},
|
|
|
|
headers={'X-Put-Timestamp': '1',
|
|
|
|
'X-Delete-Timestamp': '0',
|
|
|
|
'X-Object-Count': '1',
|
|
|
|
'X-Bytes-Used': '2',
|
|
|
|
'X-Timestamp': normalize_timestamp(0)})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a/c2', environ={'REQUEST_METHOD': 'PUT'},
|
|
|
|
headers={'X-Put-Timestamp': '2',
|
|
|
|
'X-Delete-Timestamp': '0',
|
|
|
|
'X-Object-Count': '3',
|
|
|
|
'X-Bytes-Used': '4',
|
|
|
|
'X-Timestamp': normalize_timestamp(0)})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'GET'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 200)
|
2018-12-27 23:01:52 +00:00
|
|
|
self.assertEqual(resp.body.strip().split(b'\n'),
|
|
|
|
[b'c1', b'c2'])
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.content_type, 'text/plain')
|
|
|
|
self.assertEqual(resp.charset, 'utf-8')
|
2010-07-12 17:03:45 -05:00
|
|
|
|
2012-07-31 02:26:39 +00:00
|
|
|
# test unknown format uses default plain
|
|
|
|
req = Request.blank('/sda1/p/a?format=somethinglese',
|
|
|
|
environ={'REQUEST_METHOD': 'GET'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 200)
|
2018-12-27 23:01:52 +00:00
|
|
|
self.assertEqual(resp.body.strip().split(b'\n'),
|
|
|
|
[b'c1', b'c2'])
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.content_type, 'text/plain')
|
|
|
|
self.assertEqual(resp.charset, 'utf-8')
|
2012-07-31 02:26:39 +00:00
|
|
|
|
2010-07-12 17:03:45 -05:00
|
|
|
def test_GET_with_containers_json(self):
|
Support last modified on listing containers
For now, last modified timestamp is supported only on
object listing. (i.e. GET container)
For example:
GET container with json format results in like as:
[{"hash": "d41d8cd98f00b204e9800998ecf8427e", "last_modified":
"2015-06-10T04:58:23.460230", "bytes": 0, "name": "object",
"content_type": "application/octet-stream"}]
However, container listing (i.e. GET account) shows just a dict
consists of ("name", "bytes", "name") for each container.
For example:
GET accounts with json format result in like as:
[{"count": 0, "bytes": 0, "name": "container"}]
This patch is for supporting last_modified key in the container
listing results as well as object listing like as:
[{"count": 0, "bytes": 0, "name": "container", "last_modified":
"2015-06-10T04:58:23.460230"}]
This patch is changing just output for listing. The original
timestamp to show the last modified is already in container table
of account.db as a "put_timestamp" column.
Note that this patch *DOESN'T* change the put_timestamp semantics.
i.e. the last_modified timestamp will be changed only at both PUT
container and POST container.
(PUT object doesn't affect the timestamp)
Note that the tuple format of returning value from
swift.account.backend.AccountBroker.list_containers is now
(name, object_count, bytes_used, put_timestamp, 0)
* put_timestamp is added *
Original discussion was in working session at Vancouver Summit.
Etherpads are around here:
https://etherpad.openstack.org/p/liberty-swift-contributors-meetup
https://etherpad.openstack.org/p/liberty-container-listing-update
DocImpact
Change-Id: Iba0503916f1481a20c59ae9136436f40183e4c5b
2014-12-15 20:45:41 -08:00
|
|
|
put_timestamps = {}
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'PUT',
|
2013-09-01 01:54:03 -04:00
|
|
|
'HTTP_X_TIMESTAMP': '0'})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
Support last modified on listing containers
For now, last modified timestamp is supported only on
object listing. (i.e. GET container)
For example:
GET container with json format results in like as:
[{"hash": "d41d8cd98f00b204e9800998ecf8427e", "last_modified":
"2015-06-10T04:58:23.460230", "bytes": 0, "name": "object",
"content_type": "application/octet-stream"}]
However, container listing (i.e. GET account) shows just a dict
consists of ("name", "bytes", "name") for each container.
For example:
GET accounts with json format result in like as:
[{"count": 0, "bytes": 0, "name": "container"}]
This patch is for supporting last_modified key in the container
listing results as well as object listing like as:
[{"count": 0, "bytes": 0, "name": "container", "last_modified":
"2015-06-10T04:58:23.460230"}]
This patch is changing just output for listing. The original
timestamp to show the last modified is already in container table
of account.db as a "put_timestamp" column.
Note that this patch *DOESN'T* change the put_timestamp semantics.
i.e. the last_modified timestamp will be changed only at both PUT
container and POST container.
(PUT object doesn't affect the timestamp)
Note that the tuple format of returning value from
swift.account.backend.AccountBroker.list_containers is now
(name, object_count, bytes_used, put_timestamp, 0)
* put_timestamp is added *
Original discussion was in working session at Vancouver Summit.
Etherpads are around here:
https://etherpad.openstack.org/p/liberty-swift-contributors-meetup
https://etherpad.openstack.org/p/liberty-container-listing-update
DocImpact
Change-Id: Iba0503916f1481a20c59ae9136436f40183e4c5b
2014-12-15 20:45:41 -08:00
|
|
|
put_timestamps['c1'] = normalize_timestamp(1)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a/c1', environ={'REQUEST_METHOD': 'PUT'},
|
Support last modified on listing containers
For now, last modified timestamp is supported only on
object listing. (i.e. GET container)
For example:
GET container with json format results in like as:
[{"hash": "d41d8cd98f00b204e9800998ecf8427e", "last_modified":
"2015-06-10T04:58:23.460230", "bytes": 0, "name": "object",
"content_type": "application/octet-stream"}]
However, container listing (i.e. GET account) shows just a dict
consists of ("name", "bytes", "name") for each container.
For example:
GET accounts with json format result in like as:
[{"count": 0, "bytes": 0, "name": "container"}]
This patch is for supporting last_modified key in the container
listing results as well as object listing like as:
[{"count": 0, "bytes": 0, "name": "container", "last_modified":
"2015-06-10T04:58:23.460230"}]
This patch is changing just output for listing. The original
timestamp to show the last modified is already in container table
of account.db as a "put_timestamp" column.
Note that this patch *DOESN'T* change the put_timestamp semantics.
i.e. the last_modified timestamp will be changed only at both PUT
container and POST container.
(PUT object doesn't affect the timestamp)
Note that the tuple format of returning value from
swift.account.backend.AccountBroker.list_containers is now
(name, object_count, bytes_used, put_timestamp, 0)
* put_timestamp is added *
Original discussion was in working session at Vancouver Summit.
Etherpads are around here:
https://etherpad.openstack.org/p/liberty-swift-contributors-meetup
https://etherpad.openstack.org/p/liberty-container-listing-update
DocImpact
Change-Id: Iba0503916f1481a20c59ae9136436f40183e4c5b
2014-12-15 20:45:41 -08:00
|
|
|
headers={'X-Put-Timestamp': put_timestamps['c1'],
|
2010-07-12 17:03:45 -05:00
|
|
|
'X-Delete-Timestamp': '0',
|
|
|
|
'X-Object-Count': '0',
|
|
|
|
'X-Bytes-Used': '0',
|
|
|
|
'X-Timestamp': normalize_timestamp(0)})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
Support last modified on listing containers
For now, last modified timestamp is supported only on
object listing. (i.e. GET container)
For example:
GET container with json format results in like as:
[{"hash": "d41d8cd98f00b204e9800998ecf8427e", "last_modified":
"2015-06-10T04:58:23.460230", "bytes": 0, "name": "object",
"content_type": "application/octet-stream"}]
However, container listing (i.e. GET account) shows just a dict
consists of ("name", "bytes", "name") for each container.
For example:
GET accounts with json format result in like as:
[{"count": 0, "bytes": 0, "name": "container"}]
This patch is for supporting last_modified key in the container
listing results as well as object listing like as:
[{"count": 0, "bytes": 0, "name": "container", "last_modified":
"2015-06-10T04:58:23.460230"}]
This patch is changing just output for listing. The original
timestamp to show the last modified is already in container table
of account.db as a "put_timestamp" column.
Note that this patch *DOESN'T* change the put_timestamp semantics.
i.e. the last_modified timestamp will be changed only at both PUT
container and POST container.
(PUT object doesn't affect the timestamp)
Note that the tuple format of returning value from
swift.account.backend.AccountBroker.list_containers is now
(name, object_count, bytes_used, put_timestamp, 0)
* put_timestamp is added *
Original discussion was in working session at Vancouver Summit.
Etherpads are around here:
https://etherpad.openstack.org/p/liberty-swift-contributors-meetup
https://etherpad.openstack.org/p/liberty-container-listing-update
DocImpact
Change-Id: Iba0503916f1481a20c59ae9136436f40183e4c5b
2014-12-15 20:45:41 -08:00
|
|
|
put_timestamps['c2'] = normalize_timestamp(2)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a/c2', environ={'REQUEST_METHOD': 'PUT'},
|
Support last modified on listing containers
For now, last modified timestamp is supported only on
object listing. (i.e. GET container)
For example:
GET container with json format results in like as:
[{"hash": "d41d8cd98f00b204e9800998ecf8427e", "last_modified":
"2015-06-10T04:58:23.460230", "bytes": 0, "name": "object",
"content_type": "application/octet-stream"}]
However, container listing (i.e. GET account) shows just a dict
consists of ("name", "bytes", "name") for each container.
For example:
GET accounts with json format result in like as:
[{"count": 0, "bytes": 0, "name": "container"}]
This patch is for supporting last_modified key in the container
listing results as well as object listing like as:
[{"count": 0, "bytes": 0, "name": "container", "last_modified":
"2015-06-10T04:58:23.460230"}]
This patch is changing just output for listing. The original
timestamp to show the last modified is already in container table
of account.db as a "put_timestamp" column.
Note that this patch *DOESN'T* change the put_timestamp semantics.
i.e. the last_modified timestamp will be changed only at both PUT
container and POST container.
(PUT object doesn't affect the timestamp)
Note that the tuple format of returning value from
swift.account.backend.AccountBroker.list_containers is now
(name, object_count, bytes_used, put_timestamp, 0)
* put_timestamp is added *
Original discussion was in working session at Vancouver Summit.
Etherpads are around here:
https://etherpad.openstack.org/p/liberty-swift-contributors-meetup
https://etherpad.openstack.org/p/liberty-container-listing-update
DocImpact
Change-Id: Iba0503916f1481a20c59ae9136436f40183e4c5b
2014-12-15 20:45:41 -08:00
|
|
|
headers={'X-Put-Timestamp': put_timestamps['c2'],
|
2010-07-12 17:03:45 -05:00
|
|
|
'X-Delete-Timestamp': '0',
|
|
|
|
'X-Object-Count': '0',
|
|
|
|
'X-Bytes-Used': '0',
|
|
|
|
'X-Timestamp': normalize_timestamp(0)})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a?format=json',
|
|
|
|
environ={'REQUEST_METHOD': 'GET'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 200)
|
Support last modified on listing containers
For now, last modified timestamp is supported only on
object listing. (i.e. GET container)
For example:
GET container with json format results in like as:
[{"hash": "d41d8cd98f00b204e9800998ecf8427e", "last_modified":
"2015-06-10T04:58:23.460230", "bytes": 0, "name": "object",
"content_type": "application/octet-stream"}]
However, container listing (i.e. GET account) shows just a dict
consists of ("name", "bytes", "name") for each container.
For example:
GET accounts with json format result in like as:
[{"count": 0, "bytes": 0, "name": "container"}]
This patch is for supporting last_modified key in the container
listing results as well as object listing like as:
[{"count": 0, "bytes": 0, "name": "container", "last_modified":
"2015-06-10T04:58:23.460230"}]
This patch is changing just output for listing. The original
timestamp to show the last modified is already in container table
of account.db as a "put_timestamp" column.
Note that this patch *DOESN'T* change the put_timestamp semantics.
i.e. the last_modified timestamp will be changed only at both PUT
container and POST container.
(PUT object doesn't affect the timestamp)
Note that the tuple format of returning value from
swift.account.backend.AccountBroker.list_containers is now
(name, object_count, bytes_used, put_timestamp, 0)
* put_timestamp is added *
Original discussion was in working session at Vancouver Summit.
Etherpads are around here:
https://etherpad.openstack.org/p/liberty-swift-contributors-meetup
https://etherpad.openstack.org/p/liberty-container-listing-update
DocImpact
Change-Id: Iba0503916f1481a20c59ae9136436f40183e4c5b
2014-12-15 20:45:41 -08:00
|
|
|
self.assertEqual(
|
|
|
|
json.loads(resp.body),
|
|
|
|
[{'count': 0, 'bytes': 0, 'name': 'c1',
|
|
|
|
'last_modified': Timestamp(put_timestamps['c1']).isoformat},
|
|
|
|
{'count': 0, 'bytes': 0, 'name': 'c2',
|
|
|
|
'last_modified': Timestamp(put_timestamps['c2']).isoformat}])
|
|
|
|
put_timestamps['c1'] = normalize_timestamp(3)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a/c1', environ={'REQUEST_METHOD': 'PUT'},
|
Support last modified on listing containers
For now, last modified timestamp is supported only on
object listing. (i.e. GET container)
For example:
GET container with json format results in like as:
[{"hash": "d41d8cd98f00b204e9800998ecf8427e", "last_modified":
"2015-06-10T04:58:23.460230", "bytes": 0, "name": "object",
"content_type": "application/octet-stream"}]
However, container listing (i.e. GET account) shows just a dict
consists of ("name", "bytes", "name") for each container.
For example:
GET accounts with json format result in like as:
[{"count": 0, "bytes": 0, "name": "container"}]
This patch is for supporting last_modified key in the container
listing results as well as object listing like as:
[{"count": 0, "bytes": 0, "name": "container", "last_modified":
"2015-06-10T04:58:23.460230"}]
This patch is changing just output for listing. The original
timestamp to show the last modified is already in container table
of account.db as a "put_timestamp" column.
Note that this patch *DOESN'T* change the put_timestamp semantics.
i.e. the last_modified timestamp will be changed only at both PUT
container and POST container.
(PUT object doesn't affect the timestamp)
Note that the tuple format of returning value from
swift.account.backend.AccountBroker.list_containers is now
(name, object_count, bytes_used, put_timestamp, 0)
* put_timestamp is added *
Original discussion was in working session at Vancouver Summit.
Etherpads are around here:
https://etherpad.openstack.org/p/liberty-swift-contributors-meetup
https://etherpad.openstack.org/p/liberty-container-listing-update
DocImpact
Change-Id: Iba0503916f1481a20c59ae9136436f40183e4c5b
2014-12-15 20:45:41 -08:00
|
|
|
headers={'X-Put-Timestamp': put_timestamps['c1'],
|
2010-07-12 17:03:45 -05:00
|
|
|
'X-Delete-Timestamp': '0',
|
|
|
|
'X-Object-Count': '1',
|
|
|
|
'X-Bytes-Used': '2',
|
|
|
|
'X-Timestamp': normalize_timestamp(0)})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
Support last modified on listing containers
For now, last modified timestamp is supported only on
object listing. (i.e. GET container)
For example:
GET container with json format results in like as:
[{"hash": "d41d8cd98f00b204e9800998ecf8427e", "last_modified":
"2015-06-10T04:58:23.460230", "bytes": 0, "name": "object",
"content_type": "application/octet-stream"}]
However, container listing (i.e. GET account) shows just a dict
consists of ("name", "bytes", "name") for each container.
For example:
GET accounts with json format result in like as:
[{"count": 0, "bytes": 0, "name": "container"}]
This patch is for supporting last_modified key in the container
listing results as well as object listing like as:
[{"count": 0, "bytes": 0, "name": "container", "last_modified":
"2015-06-10T04:58:23.460230"}]
This patch is changing just output for listing. The original
timestamp to show the last modified is already in container table
of account.db as a "put_timestamp" column.
Note that this patch *DOESN'T* change the put_timestamp semantics.
i.e. the last_modified timestamp will be changed only at both PUT
container and POST container.
(PUT object doesn't affect the timestamp)
Note that the tuple format of returning value from
swift.account.backend.AccountBroker.list_containers is now
(name, object_count, bytes_used, put_timestamp, 0)
* put_timestamp is added *
Original discussion was in working session at Vancouver Summit.
Etherpads are around here:
https://etherpad.openstack.org/p/liberty-swift-contributors-meetup
https://etherpad.openstack.org/p/liberty-container-listing-update
DocImpact
Change-Id: Iba0503916f1481a20c59ae9136436f40183e4c5b
2014-12-15 20:45:41 -08:00
|
|
|
put_timestamps['c2'] = normalize_timestamp(4)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a/c2', environ={'REQUEST_METHOD': 'PUT'},
|
Support last modified on listing containers
For now, last modified timestamp is supported only on
object listing. (i.e. GET container)
For example:
GET container with json format results in like as:
[{"hash": "d41d8cd98f00b204e9800998ecf8427e", "last_modified":
"2015-06-10T04:58:23.460230", "bytes": 0, "name": "object",
"content_type": "application/octet-stream"}]
However, container listing (i.e. GET account) shows just a dict
consists of ("name", "bytes", "name") for each container.
For example:
GET accounts with json format result in like as:
[{"count": 0, "bytes": 0, "name": "container"}]
This patch is for supporting last_modified key in the container
listing results as well as object listing like as:
[{"count": 0, "bytes": 0, "name": "container", "last_modified":
"2015-06-10T04:58:23.460230"}]
This patch is changing just output for listing. The original
timestamp to show the last modified is already in container table
of account.db as a "put_timestamp" column.
Note that this patch *DOESN'T* change the put_timestamp semantics.
i.e. the last_modified timestamp will be changed only at both PUT
container and POST container.
(PUT object doesn't affect the timestamp)
Note that the tuple format of returning value from
swift.account.backend.AccountBroker.list_containers is now
(name, object_count, bytes_used, put_timestamp, 0)
* put_timestamp is added *
Original discussion was in working session at Vancouver Summit.
Etherpads are around here:
https://etherpad.openstack.org/p/liberty-swift-contributors-meetup
https://etherpad.openstack.org/p/liberty-container-listing-update
DocImpact
Change-Id: Iba0503916f1481a20c59ae9136436f40183e4c5b
2014-12-15 20:45:41 -08:00
|
|
|
headers={'X-Put-Timestamp': put_timestamps['c2'],
|
2010-07-12 17:03:45 -05:00
|
|
|
'X-Delete-Timestamp': '0',
|
|
|
|
'X-Object-Count': '3',
|
|
|
|
'X-Bytes-Used': '4',
|
|
|
|
'X-Timestamp': normalize_timestamp(0)})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a?format=json',
|
|
|
|
environ={'REQUEST_METHOD': 'GET'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 200)
|
Support last modified on listing containers
For now, last modified timestamp is supported only on
object listing. (i.e. GET container)
For example:
GET container with json format results in like as:
[{"hash": "d41d8cd98f00b204e9800998ecf8427e", "last_modified":
"2015-06-10T04:58:23.460230", "bytes": 0, "name": "object",
"content_type": "application/octet-stream"}]
However, container listing (i.e. GET account) shows just a dict
consists of ("name", "bytes", "name") for each container.
For example:
GET accounts with json format result in like as:
[{"count": 0, "bytes": 0, "name": "container"}]
This patch is for supporting last_modified key in the container
listing results as well as object listing like as:
[{"count": 0, "bytes": 0, "name": "container", "last_modified":
"2015-06-10T04:58:23.460230"}]
This patch is changing just output for listing. The original
timestamp to show the last modified is already in container table
of account.db as a "put_timestamp" column.
Note that this patch *DOESN'T* change the put_timestamp semantics.
i.e. the last_modified timestamp will be changed only at both PUT
container and POST container.
(PUT object doesn't affect the timestamp)
Note that the tuple format of returning value from
swift.account.backend.AccountBroker.list_containers is now
(name, object_count, bytes_used, put_timestamp, 0)
* put_timestamp is added *
Original discussion was in working session at Vancouver Summit.
Etherpads are around here:
https://etherpad.openstack.org/p/liberty-swift-contributors-meetup
https://etherpad.openstack.org/p/liberty-container-listing-update
DocImpact
Change-Id: Iba0503916f1481a20c59ae9136436f40183e4c5b
2014-12-15 20:45:41 -08:00
|
|
|
self.assertEqual(
|
|
|
|
json.loads(resp.body),
|
|
|
|
[{'count': 1, 'bytes': 2, 'name': 'c1',
|
|
|
|
'last_modified': Timestamp(put_timestamps['c1']).isoformat},
|
|
|
|
{'count': 3, 'bytes': 4, 'name': 'c2',
|
|
|
|
'last_modified': Timestamp(put_timestamps['c2']).isoformat}])
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.content_type, 'application/json')
|
|
|
|
self.assertEqual(resp.charset, 'utf-8')
|
2010-07-12 17:03:45 -05:00
|
|
|
|
|
|
|
def test_GET_with_containers_xml(self):
|
Support last modified on listing containers
For now, last modified timestamp is supported only on
object listing. (i.e. GET container)
For example:
GET container with json format results in like as:
[{"hash": "d41d8cd98f00b204e9800998ecf8427e", "last_modified":
"2015-06-10T04:58:23.460230", "bytes": 0, "name": "object",
"content_type": "application/octet-stream"}]
However, container listing (i.e. GET account) shows just a dict
consists of ("name", "bytes", "name") for each container.
For example:
GET accounts with json format result in like as:
[{"count": 0, "bytes": 0, "name": "container"}]
This patch is for supporting last_modified key in the container
listing results as well as object listing like as:
[{"count": 0, "bytes": 0, "name": "container", "last_modified":
"2015-06-10T04:58:23.460230"}]
This patch is changing just output for listing. The original
timestamp to show the last modified is already in container table
of account.db as a "put_timestamp" column.
Note that this patch *DOESN'T* change the put_timestamp semantics.
i.e. the last_modified timestamp will be changed only at both PUT
container and POST container.
(PUT object doesn't affect the timestamp)
Note that the tuple format of returning value from
swift.account.backend.AccountBroker.list_containers is now
(name, object_count, bytes_used, put_timestamp, 0)
* put_timestamp is added *
Original discussion was in working session at Vancouver Summit.
Etherpads are around here:
https://etherpad.openstack.org/p/liberty-swift-contributors-meetup
https://etherpad.openstack.org/p/liberty-container-listing-update
DocImpact
Change-Id: Iba0503916f1481a20c59ae9136436f40183e4c5b
2014-12-15 20:45:41 -08:00
|
|
|
put_timestamps = {}
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'PUT',
|
2013-09-01 01:54:03 -04:00
|
|
|
'HTTP_X_TIMESTAMP': '0'})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
Support last modified on listing containers
For now, last modified timestamp is supported only on
object listing. (i.e. GET container)
For example:
GET container with json format results in like as:
[{"hash": "d41d8cd98f00b204e9800998ecf8427e", "last_modified":
"2015-06-10T04:58:23.460230", "bytes": 0, "name": "object",
"content_type": "application/octet-stream"}]
However, container listing (i.e. GET account) shows just a dict
consists of ("name", "bytes", "name") for each container.
For example:
GET accounts with json format result in like as:
[{"count": 0, "bytes": 0, "name": "container"}]
This patch is for supporting last_modified key in the container
listing results as well as object listing like as:
[{"count": 0, "bytes": 0, "name": "container", "last_modified":
"2015-06-10T04:58:23.460230"}]
This patch is changing just output for listing. The original
timestamp to show the last modified is already in container table
of account.db as a "put_timestamp" column.
Note that this patch *DOESN'T* change the put_timestamp semantics.
i.e. the last_modified timestamp will be changed only at both PUT
container and POST container.
(PUT object doesn't affect the timestamp)
Note that the tuple format of returning value from
swift.account.backend.AccountBroker.list_containers is now
(name, object_count, bytes_used, put_timestamp, 0)
* put_timestamp is added *
Original discussion was in working session at Vancouver Summit.
Etherpads are around here:
https://etherpad.openstack.org/p/liberty-swift-contributors-meetup
https://etherpad.openstack.org/p/liberty-container-listing-update
DocImpact
Change-Id: Iba0503916f1481a20c59ae9136436f40183e4c5b
2014-12-15 20:45:41 -08:00
|
|
|
put_timestamps['c1'] = normalize_timestamp(1)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a/c1', environ={'REQUEST_METHOD': 'PUT'},
|
Support last modified on listing containers
For now, last modified timestamp is supported only on
object listing. (i.e. GET container)
For example:
GET container with json format results in like as:
[{"hash": "d41d8cd98f00b204e9800998ecf8427e", "last_modified":
"2015-06-10T04:58:23.460230", "bytes": 0, "name": "object",
"content_type": "application/octet-stream"}]
However, container listing (i.e. GET account) shows just a dict
consists of ("name", "bytes", "name") for each container.
For example:
GET accounts with json format result in like as:
[{"count": 0, "bytes": 0, "name": "container"}]
This patch is for supporting last_modified key in the container
listing results as well as object listing like as:
[{"count": 0, "bytes": 0, "name": "container", "last_modified":
"2015-06-10T04:58:23.460230"}]
This patch is changing just output for listing. The original
timestamp to show the last modified is already in container table
of account.db as a "put_timestamp" column.
Note that this patch *DOESN'T* change the put_timestamp semantics.
i.e. the last_modified timestamp will be changed only at both PUT
container and POST container.
(PUT object doesn't affect the timestamp)
Note that the tuple format of returning value from
swift.account.backend.AccountBroker.list_containers is now
(name, object_count, bytes_used, put_timestamp, 0)
* put_timestamp is added *
Original discussion was in working session at Vancouver Summit.
Etherpads are around here:
https://etherpad.openstack.org/p/liberty-swift-contributors-meetup
https://etherpad.openstack.org/p/liberty-container-listing-update
DocImpact
Change-Id: Iba0503916f1481a20c59ae9136436f40183e4c5b
2014-12-15 20:45:41 -08:00
|
|
|
headers={'X-Put-Timestamp': put_timestamps['c1'],
|
2010-07-12 17:03:45 -05:00
|
|
|
'X-Delete-Timestamp': '0',
|
|
|
|
'X-Object-Count': '0',
|
|
|
|
'X-Bytes-Used': '0',
|
|
|
|
'X-Timestamp': normalize_timestamp(0)})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
Support last modified on listing containers
For now, last modified timestamp is supported only on
object listing. (i.e. GET container)
For example:
GET container with json format results in like as:
[{"hash": "d41d8cd98f00b204e9800998ecf8427e", "last_modified":
"2015-06-10T04:58:23.460230", "bytes": 0, "name": "object",
"content_type": "application/octet-stream"}]
However, container listing (i.e. GET account) shows just a dict
consists of ("name", "bytes", "name") for each container.
For example:
GET accounts with json format result in like as:
[{"count": 0, "bytes": 0, "name": "container"}]
This patch is for supporting last_modified key in the container
listing results as well as object listing like as:
[{"count": 0, "bytes": 0, "name": "container", "last_modified":
"2015-06-10T04:58:23.460230"}]
This patch is changing just output for listing. The original
timestamp to show the last modified is already in container table
of account.db as a "put_timestamp" column.
Note that this patch *DOESN'T* change the put_timestamp semantics.
i.e. the last_modified timestamp will be changed only at both PUT
container and POST container.
(PUT object doesn't affect the timestamp)
Note that the tuple format of returning value from
swift.account.backend.AccountBroker.list_containers is now
(name, object_count, bytes_used, put_timestamp, 0)
* put_timestamp is added *
Original discussion was in working session at Vancouver Summit.
Etherpads are around here:
https://etherpad.openstack.org/p/liberty-swift-contributors-meetup
https://etherpad.openstack.org/p/liberty-container-listing-update
DocImpact
Change-Id: Iba0503916f1481a20c59ae9136436f40183e4c5b
2014-12-15 20:45:41 -08:00
|
|
|
put_timestamps['c2'] = normalize_timestamp(2)
|
2011-07-22 10:54:54 -07:00
|
|
|
req = Request.blank('/sda1/p/a/c2', environ={'REQUEST_METHOD': 'PUT'},
|
Support last modified on listing containers
For now, last modified timestamp is supported only on
object listing. (i.e. GET container)
For example:
GET container with json format results in like as:
[{"hash": "d41d8cd98f00b204e9800998ecf8427e", "last_modified":
"2015-06-10T04:58:23.460230", "bytes": 0, "name": "object",
"content_type": "application/octet-stream"}]
However, container listing (i.e. GET account) shows just a dict
consists of ("name", "bytes", "name") for each container.
For example:
GET accounts with json format result in like as:
[{"count": 0, "bytes": 0, "name": "container"}]
This patch is for supporting last_modified key in the container
listing results as well as object listing like as:
[{"count": 0, "bytes": 0, "name": "container", "last_modified":
"2015-06-10T04:58:23.460230"}]
This patch is changing just output for listing. The original
timestamp to show the last modified is already in container table
of account.db as a "put_timestamp" column.
Note that this patch *DOESN'T* change the put_timestamp semantics.
i.e. the last_modified timestamp will be changed only at both PUT
container and POST container.
(PUT object doesn't affect the timestamp)
Note that the tuple format of returning value from
swift.account.backend.AccountBroker.list_containers is now
(name, object_count, bytes_used, put_timestamp, 0)
* put_timestamp is added *
Original discussion was in working session at Vancouver Summit.
Etherpads are around here:
https://etherpad.openstack.org/p/liberty-swift-contributors-meetup
https://etherpad.openstack.org/p/liberty-container-listing-update
DocImpact
Change-Id: Iba0503916f1481a20c59ae9136436f40183e4c5b
2014-12-15 20:45:41 -08:00
|
|
|
headers={'X-Put-Timestamp': put_timestamps['c2'],
|
2010-07-12 17:03:45 -05:00
|
|
|
'X-Delete-Timestamp': '0',
|
|
|
|
'X-Object-Count': '0',
|
|
|
|
'X-Bytes-Used': '0',
|
|
|
|
'X-Timestamp': normalize_timestamp(0)})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a?format=xml',
|
|
|
|
environ={'REQUEST_METHOD': 'GET'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.content_type, 'application/xml')
|
|
|
|
self.assertEqual(resp.status_int, 200)
|
2011-07-22 10:54:54 -07:00
|
|
|
dom = xml.dom.minidom.parseString(resp.body)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(dom.firstChild.nodeName, 'account')
|
2010-07-12 17:03:45 -05:00
|
|
|
listing = \
|
|
|
|
[n for n in dom.firstChild.childNodes if n.nodeName != '#text']
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(len(listing), 2)
|
|
|
|
self.assertEqual(listing[0].nodeName, 'container')
|
2010-07-12 17:03:45 -05:00
|
|
|
container = [n for n in listing[0].childNodes if n.nodeName != '#text']
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(sorted([n.nodeName for n in container]),
|
Support last modified on listing containers
For now, last modified timestamp is supported only on
object listing. (i.e. GET container)
For example:
GET container with json format results in like as:
[{"hash": "d41d8cd98f00b204e9800998ecf8427e", "last_modified":
"2015-06-10T04:58:23.460230", "bytes": 0, "name": "object",
"content_type": "application/octet-stream"}]
However, container listing (i.e. GET account) shows just a dict
consists of ("name", "bytes", "name") for each container.
For example:
GET accounts with json format result in like as:
[{"count": 0, "bytes": 0, "name": "container"}]
This patch is for supporting last_modified key in the container
listing results as well as object listing like as:
[{"count": 0, "bytes": 0, "name": "container", "last_modified":
"2015-06-10T04:58:23.460230"}]
This patch is changing just output for listing. The original
timestamp to show the last modified is already in container table
of account.db as a "put_timestamp" column.
Note that this patch *DOESN'T* change the put_timestamp semantics.
i.e. the last_modified timestamp will be changed only at both PUT
container and POST container.
(PUT object doesn't affect the timestamp)
Note that the tuple format of returning value from
swift.account.backend.AccountBroker.list_containers is now
(name, object_count, bytes_used, put_timestamp, 0)
* put_timestamp is added *
Original discussion was in working session at Vancouver Summit.
Etherpads are around here:
https://etherpad.openstack.org/p/liberty-swift-contributors-meetup
https://etherpad.openstack.org/p/liberty-container-listing-update
DocImpact
Change-Id: Iba0503916f1481a20c59ae9136436f40183e4c5b
2014-12-15 20:45:41 -08:00
|
|
|
['bytes', 'count', 'last_modified', 'name'])
|
2010-07-12 17:03:45 -05:00
|
|
|
node = [n for n in container if n.nodeName == 'name'][0]
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(node.firstChild.nodeValue, 'c1')
|
2010-07-12 17:03:45 -05:00
|
|
|
node = [n for n in container if n.nodeName == 'count'][0]
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(node.firstChild.nodeValue, '0')
|
2010-07-12 17:03:45 -05:00
|
|
|
node = [n for n in container if n.nodeName == 'bytes'][0]
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(node.firstChild.nodeValue, '0')
|
Support last modified on listing containers
For now, last modified timestamp is supported only on
object listing. (i.e. GET container)
For example:
GET container with json format results in like as:
[{"hash": "d41d8cd98f00b204e9800998ecf8427e", "last_modified":
"2015-06-10T04:58:23.460230", "bytes": 0, "name": "object",
"content_type": "application/octet-stream"}]
However, container listing (i.e. GET account) shows just a dict
consists of ("name", "bytes", "name") for each container.
For example:
GET accounts with json format result in like as:
[{"count": 0, "bytes": 0, "name": "container"}]
This patch is for supporting last_modified key in the container
listing results as well as object listing like as:
[{"count": 0, "bytes": 0, "name": "container", "last_modified":
"2015-06-10T04:58:23.460230"}]
This patch is changing just output for listing. The original
timestamp to show the last modified is already in container table
of account.db as a "put_timestamp" column.
Note that this patch *DOESN'T* change the put_timestamp semantics.
i.e. the last_modified timestamp will be changed only at both PUT
container and POST container.
(PUT object doesn't affect the timestamp)
Note that the tuple format of returning value from
swift.account.backend.AccountBroker.list_containers is now
(name, object_count, bytes_used, put_timestamp, 0)
* put_timestamp is added *
Original discussion was in working session at Vancouver Summit.
Etherpads are around here:
https://etherpad.openstack.org/p/liberty-swift-contributors-meetup
https://etherpad.openstack.org/p/liberty-container-listing-update
DocImpact
Change-Id: Iba0503916f1481a20c59ae9136436f40183e4c5b
2014-12-15 20:45:41 -08:00
|
|
|
node = [n for n in container if n.nodeName == 'last_modified'][0]
|
|
|
|
self.assertEqual(node.firstChild.nodeValue,
|
|
|
|
Timestamp(put_timestamps['c1']).isoformat)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(listing[-1].nodeName, 'container')
|
2010-07-12 17:03:45 -05:00
|
|
|
container = \
|
|
|
|
[n for n in listing[-1].childNodes if n.nodeName != '#text']
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(sorted([n.nodeName for n in container]),
|
Support last modified on listing containers
For now, last modified timestamp is supported only on
object listing. (i.e. GET container)
For example:
GET container with json format results in like as:
[{"hash": "d41d8cd98f00b204e9800998ecf8427e", "last_modified":
"2015-06-10T04:58:23.460230", "bytes": 0, "name": "object",
"content_type": "application/octet-stream"}]
However, container listing (i.e. GET account) shows just a dict
consists of ("name", "bytes", "name") for each container.
For example:
GET accounts with json format result in like as:
[{"count": 0, "bytes": 0, "name": "container"}]
This patch is for supporting last_modified key in the container
listing results as well as object listing like as:
[{"count": 0, "bytes": 0, "name": "container", "last_modified":
"2015-06-10T04:58:23.460230"}]
This patch is changing just output for listing. The original
timestamp to show the last modified is already in container table
of account.db as a "put_timestamp" column.
Note that this patch *DOESN'T* change the put_timestamp semantics.
i.e. the last_modified timestamp will be changed only at both PUT
container and POST container.
(PUT object doesn't affect the timestamp)
Note that the tuple format of returning value from
swift.account.backend.AccountBroker.list_containers is now
(name, object_count, bytes_used, put_timestamp, 0)
* put_timestamp is added *
Original discussion was in working session at Vancouver Summit.
Etherpads are around here:
https://etherpad.openstack.org/p/liberty-swift-contributors-meetup
https://etherpad.openstack.org/p/liberty-container-listing-update
DocImpact
Change-Id: Iba0503916f1481a20c59ae9136436f40183e4c5b
2014-12-15 20:45:41 -08:00
|
|
|
['bytes', 'count', 'last_modified', 'name'])
|
2010-07-12 17:03:45 -05:00
|
|
|
node = [n for n in container if n.nodeName == 'name'][0]
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(node.firstChild.nodeValue, 'c2')
|
2010-07-12 17:03:45 -05:00
|
|
|
node = [n for n in container if n.nodeName == 'count'][0]
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(node.firstChild.nodeValue, '0')
|
2010-07-12 17:03:45 -05:00
|
|
|
node = [n for n in container if n.nodeName == 'bytes'][0]
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(node.firstChild.nodeValue, '0')
|
Support last modified on listing containers
For now, last modified timestamp is supported only on
object listing. (i.e. GET container)
For example:
GET container with json format results in like as:
[{"hash": "d41d8cd98f00b204e9800998ecf8427e", "last_modified":
"2015-06-10T04:58:23.460230", "bytes": 0, "name": "object",
"content_type": "application/octet-stream"}]
However, container listing (i.e. GET account) shows just a dict
consists of ("name", "bytes", "name") for each container.
For example:
GET accounts with json format result in like as:
[{"count": 0, "bytes": 0, "name": "container"}]
This patch is for supporting last_modified key in the container
listing results as well as object listing like as:
[{"count": 0, "bytes": 0, "name": "container", "last_modified":
"2015-06-10T04:58:23.460230"}]
This patch is changing just output for listing. The original
timestamp to show the last modified is already in container table
of account.db as a "put_timestamp" column.
Note that this patch *DOESN'T* change the put_timestamp semantics.
i.e. the last_modified timestamp will be changed only at both PUT
container and POST container.
(PUT object doesn't affect the timestamp)
Note that the tuple format of returning value from
swift.account.backend.AccountBroker.list_containers is now
(name, object_count, bytes_used, put_timestamp, 0)
* put_timestamp is added *
Original discussion was in working session at Vancouver Summit.
Etherpads are around here:
https://etherpad.openstack.org/p/liberty-swift-contributors-meetup
https://etherpad.openstack.org/p/liberty-container-listing-update
DocImpact
Change-Id: Iba0503916f1481a20c59ae9136436f40183e4c5b
2014-12-15 20:45:41 -08:00
|
|
|
node = [n for n in container if n.nodeName == 'last_modified'][0]
|
|
|
|
self.assertEqual(node.firstChild.nodeValue,
|
|
|
|
Timestamp(put_timestamps['c2']).isoformat)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a/c1', environ={'REQUEST_METHOD': 'PUT'},
|
|
|
|
headers={'X-Put-Timestamp': '1',
|
|
|
|
'X-Delete-Timestamp': '0',
|
|
|
|
'X-Object-Count': '1',
|
|
|
|
'X-Bytes-Used': '2',
|
|
|
|
'X-Timestamp': normalize_timestamp(0)})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2011-07-22 10:54:54 -07:00
|
|
|
req = Request.blank('/sda1/p/a/c2', environ={'REQUEST_METHOD': 'PUT'},
|
2010-07-12 17:03:45 -05:00
|
|
|
headers={'X-Put-Timestamp': '2',
|
|
|
|
'X-Delete-Timestamp': '0',
|
|
|
|
'X-Object-Count': '3',
|
|
|
|
'X-Bytes-Used': '4',
|
|
|
|
'X-Timestamp': normalize_timestamp(0)})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a?format=xml',
|
|
|
|
environ={'REQUEST_METHOD': 'GET'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 200)
|
2011-07-22 10:54:54 -07:00
|
|
|
dom = xml.dom.minidom.parseString(resp.body)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(dom.firstChild.nodeName, 'account')
|
2010-07-12 17:03:45 -05:00
|
|
|
listing = \
|
|
|
|
[n for n in dom.firstChild.childNodes if n.nodeName != '#text']
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(len(listing), 2)
|
|
|
|
self.assertEqual(listing[0].nodeName, 'container')
|
2010-07-12 17:03:45 -05:00
|
|
|
container = [n for n in listing[0].childNodes if n.nodeName != '#text']
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(sorted([n.nodeName for n in container]),
|
Support last modified on listing containers
For now, last modified timestamp is supported only on
object listing. (i.e. GET container)
For example:
GET container with json format results in like as:
[{"hash": "d41d8cd98f00b204e9800998ecf8427e", "last_modified":
"2015-06-10T04:58:23.460230", "bytes": 0, "name": "object",
"content_type": "application/octet-stream"}]
However, container listing (i.e. GET account) shows just a dict
consists of ("name", "bytes", "name") for each container.
For example:
GET accounts with json format result in like as:
[{"count": 0, "bytes": 0, "name": "container"}]
This patch is for supporting last_modified key in the container
listing results as well as object listing like as:
[{"count": 0, "bytes": 0, "name": "container", "last_modified":
"2015-06-10T04:58:23.460230"}]
This patch is changing just output for listing. The original
timestamp to show the last modified is already in container table
of account.db as a "put_timestamp" column.
Note that this patch *DOESN'T* change the put_timestamp semantics.
i.e. the last_modified timestamp will be changed only at both PUT
container and POST container.
(PUT object doesn't affect the timestamp)
Note that the tuple format of returning value from
swift.account.backend.AccountBroker.list_containers is now
(name, object_count, bytes_used, put_timestamp, 0)
* put_timestamp is added *
Original discussion was in working session at Vancouver Summit.
Etherpads are around here:
https://etherpad.openstack.org/p/liberty-swift-contributors-meetup
https://etherpad.openstack.org/p/liberty-container-listing-update
DocImpact
Change-Id: Iba0503916f1481a20c59ae9136436f40183e4c5b
2014-12-15 20:45:41 -08:00
|
|
|
['bytes', 'count', 'last_modified', 'name'])
|
2010-07-12 17:03:45 -05:00
|
|
|
node = [n for n in container if n.nodeName == 'name'][0]
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(node.firstChild.nodeValue, 'c1')
|
2010-07-12 17:03:45 -05:00
|
|
|
node = [n for n in container if n.nodeName == 'count'][0]
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(node.firstChild.nodeValue, '1')
|
2010-07-12 17:03:45 -05:00
|
|
|
node = [n for n in container if n.nodeName == 'bytes'][0]
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(node.firstChild.nodeValue, '2')
|
Support last modified on listing containers
For now, last modified timestamp is supported only on
object listing. (i.e. GET container)
For example:
GET container with json format results in like as:
[{"hash": "d41d8cd98f00b204e9800998ecf8427e", "last_modified":
"2015-06-10T04:58:23.460230", "bytes": 0, "name": "object",
"content_type": "application/octet-stream"}]
However, container listing (i.e. GET account) shows just a dict
consists of ("name", "bytes", "name") for each container.
For example:
GET accounts with json format result in like as:
[{"count": 0, "bytes": 0, "name": "container"}]
This patch is for supporting last_modified key in the container
listing results as well as object listing like as:
[{"count": 0, "bytes": 0, "name": "container", "last_modified":
"2015-06-10T04:58:23.460230"}]
This patch is changing just output for listing. The original
timestamp to show the last modified is already in container table
of account.db as a "put_timestamp" column.
Note that this patch *DOESN'T* change the put_timestamp semantics.
i.e. the last_modified timestamp will be changed only at both PUT
container and POST container.
(PUT object doesn't affect the timestamp)
Note that the tuple format of returning value from
swift.account.backend.AccountBroker.list_containers is now
(name, object_count, bytes_used, put_timestamp, 0)
* put_timestamp is added *
Original discussion was in working session at Vancouver Summit.
Etherpads are around here:
https://etherpad.openstack.org/p/liberty-swift-contributors-meetup
https://etherpad.openstack.org/p/liberty-container-listing-update
DocImpact
Change-Id: Iba0503916f1481a20c59ae9136436f40183e4c5b
2014-12-15 20:45:41 -08:00
|
|
|
node = [n for n in container if n.nodeName == 'last_modified'][0]
|
|
|
|
self.assertEqual(node.firstChild.nodeValue,
|
|
|
|
Timestamp(put_timestamps['c1']).isoformat)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(listing[-1].nodeName, 'container')
|
2013-09-01 01:54:03 -04:00
|
|
|
container = [
|
|
|
|
n for n in listing[-1].childNodes if n.nodeName != '#text']
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(sorted([n.nodeName for n in container]),
|
Support last modified on listing containers
For now, last modified timestamp is supported only on
object listing. (i.e. GET container)
For example:
GET container with json format results in like as:
[{"hash": "d41d8cd98f00b204e9800998ecf8427e", "last_modified":
"2015-06-10T04:58:23.460230", "bytes": 0, "name": "object",
"content_type": "application/octet-stream"}]
However, container listing (i.e. GET account) shows just a dict
consists of ("name", "bytes", "name") for each container.
For example:
GET accounts with json format result in like as:
[{"count": 0, "bytes": 0, "name": "container"}]
This patch is for supporting last_modified key in the container
listing results as well as object listing like as:
[{"count": 0, "bytes": 0, "name": "container", "last_modified":
"2015-06-10T04:58:23.460230"}]
This patch is changing just output for listing. The original
timestamp to show the last modified is already in container table
of account.db as a "put_timestamp" column.
Note that this patch *DOESN'T* change the put_timestamp semantics.
i.e. the last_modified timestamp will be changed only at both PUT
container and POST container.
(PUT object doesn't affect the timestamp)
Note that the tuple format of returning value from
swift.account.backend.AccountBroker.list_containers is now
(name, object_count, bytes_used, put_timestamp, 0)
* put_timestamp is added *
Original discussion was in working session at Vancouver Summit.
Etherpads are around here:
https://etherpad.openstack.org/p/liberty-swift-contributors-meetup
https://etherpad.openstack.org/p/liberty-container-listing-update
DocImpact
Change-Id: Iba0503916f1481a20c59ae9136436f40183e4c5b
2014-12-15 20:45:41 -08:00
|
|
|
['bytes', 'count', 'last_modified', 'name'])
|
2010-07-12 17:03:45 -05:00
|
|
|
node = [n for n in container if n.nodeName == 'name'][0]
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(node.firstChild.nodeValue, 'c2')
|
2010-07-12 17:03:45 -05:00
|
|
|
node = [n for n in container if n.nodeName == 'count'][0]
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(node.firstChild.nodeValue, '3')
|
2010-07-12 17:03:45 -05:00
|
|
|
node = [n for n in container if n.nodeName == 'bytes'][0]
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(node.firstChild.nodeValue, '4')
|
Support last modified on listing containers
For now, last modified timestamp is supported only on
object listing. (i.e. GET container)
For example:
GET container with json format results in like as:
[{"hash": "d41d8cd98f00b204e9800998ecf8427e", "last_modified":
"2015-06-10T04:58:23.460230", "bytes": 0, "name": "object",
"content_type": "application/octet-stream"}]
However, container listing (i.e. GET account) shows just a dict
consists of ("name", "bytes", "name") for each container.
For example:
GET accounts with json format result in like as:
[{"count": 0, "bytes": 0, "name": "container"}]
This patch is for supporting last_modified key in the container
listing results as well as object listing like as:
[{"count": 0, "bytes": 0, "name": "container", "last_modified":
"2015-06-10T04:58:23.460230"}]
This patch is changing just output for listing. The original
timestamp to show the last modified is already in container table
of account.db as a "put_timestamp" column.
Note that this patch *DOESN'T* change the put_timestamp semantics.
i.e. the last_modified timestamp will be changed only at both PUT
container and POST container.
(PUT object doesn't affect the timestamp)
Note that the tuple format of returning value from
swift.account.backend.AccountBroker.list_containers is now
(name, object_count, bytes_used, put_timestamp, 0)
* put_timestamp is added *
Original discussion was in working session at Vancouver Summit.
Etherpads are around here:
https://etherpad.openstack.org/p/liberty-swift-contributors-meetup
https://etherpad.openstack.org/p/liberty-container-listing-update
DocImpact
Change-Id: Iba0503916f1481a20c59ae9136436f40183e4c5b
2014-12-15 20:45:41 -08:00
|
|
|
node = [n for n in container if n.nodeName == 'last_modified'][0]
|
|
|
|
self.assertEqual(node.firstChild.nodeValue,
|
|
|
|
Timestamp(put_timestamps['c2']).isoformat)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.charset, 'utf-8')
|
2010-07-12 17:03:45 -05:00
|
|
|
|
2013-06-13 11:13:36 -07:00
|
|
|
def test_GET_xml_escapes_account_name(self):
|
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/%22%27', # "'
|
|
|
|
environ={'REQUEST_METHOD': 'PUT', 'HTTP_X_TIMESTAMP': '0'})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2013-06-13 11:13:36 -07:00
|
|
|
|
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/%22%27?format=xml',
|
|
|
|
environ={'REQUEST_METHOD': 'GET', 'HTTP_X_TIMESTAMP': '1'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-06-13 11:13:36 -07:00
|
|
|
|
|
|
|
dom = xml.dom.minidom.parseString(resp.body)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(dom.firstChild.attributes['name'].value, '"\'')
|
2013-06-13 11:13:36 -07:00
|
|
|
|
|
|
|
def test_GET_xml_escapes_container_name(self):
|
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a',
|
|
|
|
environ={'REQUEST_METHOD': 'PUT', 'HTTP_X_TIMESTAMP': '0'})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2013-06-13 11:13:36 -07:00
|
|
|
|
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a/%22%3Cword', # "<word
|
|
|
|
environ={'REQUEST_METHOD': 'PUT', 'HTTP_X_TIMESTAMP': '1',
|
|
|
|
'HTTP_X_PUT_TIMESTAMP': '1', 'HTTP_X_OBJECT_COUNT': '0',
|
|
|
|
'HTTP_X_DELETE_TIMESTAMP': '0', 'HTTP_X_BYTES_USED': '1'})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2013-06-13 11:13:36 -07:00
|
|
|
|
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a?format=xml',
|
|
|
|
environ={'REQUEST_METHOD': 'GET', 'HTTP_X_TIMESTAMP': '1'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-06-13 11:13:36 -07:00
|
|
|
dom = xml.dom.minidom.parseString(resp.body)
|
|
|
|
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(
|
2013-06-13 11:13:36 -07:00
|
|
|
dom.firstChild.firstChild.nextSibling.firstChild.firstChild.data,
|
|
|
|
'"<word')
|
|
|
|
|
2013-06-14 15:29:08 +00:00
|
|
|
def test_GET_xml_escapes_container_name_as_subdir(self):
|
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a',
|
|
|
|
environ={'REQUEST_METHOD': 'PUT', 'HTTP_X_TIMESTAMP': '0'})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2013-06-14 15:29:08 +00:00
|
|
|
|
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a/%22%3Cword-test', # "<word-test
|
|
|
|
environ={'REQUEST_METHOD': 'PUT', 'HTTP_X_TIMESTAMP': '1',
|
|
|
|
'HTTP_X_PUT_TIMESTAMP': '1', 'HTTP_X_OBJECT_COUNT': '0',
|
|
|
|
'HTTP_X_DELETE_TIMESTAMP': '0', 'HTTP_X_BYTES_USED': '1'})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2013-06-14 15:29:08 +00:00
|
|
|
|
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a?format=xml&delimiter=-',
|
|
|
|
environ={'REQUEST_METHOD': 'GET', 'HTTP_X_TIMESTAMP': '1'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-06-14 15:29:08 +00:00
|
|
|
dom = xml.dom.minidom.parseString(resp.body)
|
|
|
|
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(
|
2013-06-14 15:29:08 +00:00
|
|
|
dom.firstChild.firstChild.nextSibling.attributes['name'].value,
|
|
|
|
'"<word-')
|
|
|
|
|
2010-07-12 17:03:45 -05:00
|
|
|
def test_GET_limit_marker_plain(self):
|
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'PUT',
|
2013-09-01 01:54:03 -04:00
|
|
|
'HTTP_X_TIMESTAMP': '0'})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
Support last modified on listing containers
For now, last modified timestamp is supported only on
object listing. (i.e. GET container)
For example:
GET container with json format results in like as:
[{"hash": "d41d8cd98f00b204e9800998ecf8427e", "last_modified":
"2015-06-10T04:58:23.460230", "bytes": 0, "name": "object",
"content_type": "application/octet-stream"}]
However, container listing (i.e. GET account) shows just a dict
consists of ("name", "bytes", "name") for each container.
For example:
GET accounts with json format result in like as:
[{"count": 0, "bytes": 0, "name": "container"}]
This patch is for supporting last_modified key in the container
listing results as well as object listing like as:
[{"count": 0, "bytes": 0, "name": "container", "last_modified":
"2015-06-10T04:58:23.460230"}]
This patch is changing just output for listing. The original
timestamp to show the last modified is already in container table
of account.db as a "put_timestamp" column.
Note that this patch *DOESN'T* change the put_timestamp semantics.
i.e. the last_modified timestamp will be changed only at both PUT
container and POST container.
(PUT object doesn't affect the timestamp)
Note that the tuple format of returning value from
swift.account.backend.AccountBroker.list_containers is now
(name, object_count, bytes_used, put_timestamp, 0)
* put_timestamp is added *
Original discussion was in working session at Vancouver Summit.
Etherpads are around here:
https://etherpad.openstack.org/p/liberty-swift-contributors-meetup
https://etherpad.openstack.org/p/liberty-container-listing-update
DocImpact
Change-Id: Iba0503916f1481a20c59ae9136436f40183e4c5b
2014-12-15 20:45:41 -08:00
|
|
|
put_timestamp = normalize_timestamp(0)
|
2015-05-25 18:28:02 +02:00
|
|
|
for c in range(5):
|
2013-09-01 01:54:03 -04:00
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a/c%d' % c,
|
|
|
|
environ={'REQUEST_METHOD': 'PUT'},
|
Support last modified on listing containers
For now, last modified timestamp is supported only on
object listing. (i.e. GET container)
For example:
GET container with json format results in like as:
[{"hash": "d41d8cd98f00b204e9800998ecf8427e", "last_modified":
"2015-06-10T04:58:23.460230", "bytes": 0, "name": "object",
"content_type": "application/octet-stream"}]
However, container listing (i.e. GET account) shows just a dict
consists of ("name", "bytes", "name") for each container.
For example:
GET accounts with json format result in like as:
[{"count": 0, "bytes": 0, "name": "container"}]
This patch is for supporting last_modified key in the container
listing results as well as object listing like as:
[{"count": 0, "bytes": 0, "name": "container", "last_modified":
"2015-06-10T04:58:23.460230"}]
This patch is changing just output for listing. The original
timestamp to show the last modified is already in container table
of account.db as a "put_timestamp" column.
Note that this patch *DOESN'T* change the put_timestamp semantics.
i.e. the last_modified timestamp will be changed only at both PUT
container and POST container.
(PUT object doesn't affect the timestamp)
Note that the tuple format of returning value from
swift.account.backend.AccountBroker.list_containers is now
(name, object_count, bytes_used, put_timestamp, 0)
* put_timestamp is added *
Original discussion was in working session at Vancouver Summit.
Etherpads are around here:
https://etherpad.openstack.org/p/liberty-swift-contributors-meetup
https://etherpad.openstack.org/p/liberty-container-listing-update
DocImpact
Change-Id: Iba0503916f1481a20c59ae9136436f40183e4c5b
2014-12-15 20:45:41 -08:00
|
|
|
headers={'X-Put-Timestamp': put_timestamp,
|
2013-09-01 01:54:03 -04:00
|
|
|
'X-Delete-Timestamp': '0',
|
|
|
|
'X-Object-Count': '2',
|
|
|
|
'X-Bytes-Used': '3',
|
Support last modified on listing containers
For now, last modified timestamp is supported only on
object listing. (i.e. GET container)
For example:
GET container with json format results in like as:
[{"hash": "d41d8cd98f00b204e9800998ecf8427e", "last_modified":
"2015-06-10T04:58:23.460230", "bytes": 0, "name": "object",
"content_type": "application/octet-stream"}]
However, container listing (i.e. GET account) shows just a dict
consists of ("name", "bytes", "name") for each container.
For example:
GET accounts with json format result in like as:
[{"count": 0, "bytes": 0, "name": "container"}]
This patch is for supporting last_modified key in the container
listing results as well as object listing like as:
[{"count": 0, "bytes": 0, "name": "container", "last_modified":
"2015-06-10T04:58:23.460230"}]
This patch is changing just output for listing. The original
timestamp to show the last modified is already in container table
of account.db as a "put_timestamp" column.
Note that this patch *DOESN'T* change the put_timestamp semantics.
i.e. the last_modified timestamp will be changed only at both PUT
container and POST container.
(PUT object doesn't affect the timestamp)
Note that the tuple format of returning value from
swift.account.backend.AccountBroker.list_containers is now
(name, object_count, bytes_used, put_timestamp, 0)
* put_timestamp is added *
Original discussion was in working session at Vancouver Summit.
Etherpads are around here:
https://etherpad.openstack.org/p/liberty-swift-contributors-meetup
https://etherpad.openstack.org/p/liberty-container-listing-update
DocImpact
Change-Id: Iba0503916f1481a20c59ae9136436f40183e4c5b
2014-12-15 20:45:41 -08:00
|
|
|
'X-Timestamp': put_timestamp})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a?limit=3',
|
|
|
|
environ={'REQUEST_METHOD': 'GET'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 200)
|
2018-12-27 23:01:52 +00:00
|
|
|
self.assertEqual(resp.body.strip().split(b'\n'),
|
|
|
|
[b'c0', b'c1', b'c2'])
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a?limit=3&marker=c2',
|
|
|
|
environ={'REQUEST_METHOD': 'GET'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 200)
|
2018-12-27 23:01:52 +00:00
|
|
|
self.assertEqual(resp.body.strip().split(b'\n'),
|
|
|
|
[b'c3', b'c4'])
|
2010-07-12 17:03:45 -05:00
|
|
|
|
|
|
|
def test_GET_limit_marker_json(self):
|
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'PUT',
|
2013-09-01 01:54:03 -04:00
|
|
|
'HTTP_X_TIMESTAMP': '0'})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2015-05-25 18:28:02 +02:00
|
|
|
for c in range(5):
|
2017-01-12 18:04:40 +00:00
|
|
|
put_timestamp = normalize_timestamp(c + 1)
|
2013-09-01 01:54:03 -04:00
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a/c%d' % c,
|
|
|
|
environ={'REQUEST_METHOD': 'PUT'},
|
Support last modified on listing containers
For now, last modified timestamp is supported only on
object listing. (i.e. GET container)
For example:
GET container with json format results in like as:
[{"hash": "d41d8cd98f00b204e9800998ecf8427e", "last_modified":
"2015-06-10T04:58:23.460230", "bytes": 0, "name": "object",
"content_type": "application/octet-stream"}]
However, container listing (i.e. GET account) shows just a dict
consists of ("name", "bytes", "name") for each container.
For example:
GET accounts with json format result in like as:
[{"count": 0, "bytes": 0, "name": "container"}]
This patch is for supporting last_modified key in the container
listing results as well as object listing like as:
[{"count": 0, "bytes": 0, "name": "container", "last_modified":
"2015-06-10T04:58:23.460230"}]
This patch is changing just output for listing. The original
timestamp to show the last modified is already in container table
of account.db as a "put_timestamp" column.
Note that this patch *DOESN'T* change the put_timestamp semantics.
i.e. the last_modified timestamp will be changed only at both PUT
container and POST container.
(PUT object doesn't affect the timestamp)
Note that the tuple format of returning value from
swift.account.backend.AccountBroker.list_containers is now
(name, object_count, bytes_used, put_timestamp, 0)
* put_timestamp is added *
Original discussion was in working session at Vancouver Summit.
Etherpads are around here:
https://etherpad.openstack.org/p/liberty-swift-contributors-meetup
https://etherpad.openstack.org/p/liberty-container-listing-update
DocImpact
Change-Id: Iba0503916f1481a20c59ae9136436f40183e4c5b
2014-12-15 20:45:41 -08:00
|
|
|
headers={'X-Put-Timestamp': put_timestamp,
|
2013-09-01 01:54:03 -04:00
|
|
|
'X-Delete-Timestamp': '0',
|
|
|
|
'X-Object-Count': '2',
|
|
|
|
'X-Bytes-Used': '3',
|
Support last modified on listing containers
For now, last modified timestamp is supported only on
object listing. (i.e. GET container)
For example:
GET container with json format results in like as:
[{"hash": "d41d8cd98f00b204e9800998ecf8427e", "last_modified":
"2015-06-10T04:58:23.460230", "bytes": 0, "name": "object",
"content_type": "application/octet-stream"}]
However, container listing (i.e. GET account) shows just a dict
consists of ("name", "bytes", "name") for each container.
For example:
GET accounts with json format result in like as:
[{"count": 0, "bytes": 0, "name": "container"}]
This patch is for supporting last_modified key in the container
listing results as well as object listing like as:
[{"count": 0, "bytes": 0, "name": "container", "last_modified":
"2015-06-10T04:58:23.460230"}]
This patch is changing just output for listing. The original
timestamp to show the last modified is already in container table
of account.db as a "put_timestamp" column.
Note that this patch *DOESN'T* change the put_timestamp semantics.
i.e. the last_modified timestamp will be changed only at both PUT
container and POST container.
(PUT object doesn't affect the timestamp)
Note that the tuple format of returning value from
swift.account.backend.AccountBroker.list_containers is now
(name, object_count, bytes_used, put_timestamp, 0)
* put_timestamp is added *
Original discussion was in working session at Vancouver Summit.
Etherpads are around here:
https://etherpad.openstack.org/p/liberty-swift-contributors-meetup
https://etherpad.openstack.org/p/liberty-container-listing-update
DocImpact
Change-Id: Iba0503916f1481a20c59ae9136436f40183e4c5b
2014-12-15 20:45:41 -08:00
|
|
|
'X-Timestamp': put_timestamp})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a?limit=3&format=json',
|
|
|
|
environ={'REQUEST_METHOD': 'GET'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 200)
|
Support last modified on listing containers
For now, last modified timestamp is supported only on
object listing. (i.e. GET container)
For example:
GET container with json format results in like as:
[{"hash": "d41d8cd98f00b204e9800998ecf8427e", "last_modified":
"2015-06-10T04:58:23.460230", "bytes": 0, "name": "object",
"content_type": "application/octet-stream"}]
However, container listing (i.e. GET account) shows just a dict
consists of ("name", "bytes", "name") for each container.
For example:
GET accounts with json format result in like as:
[{"count": 0, "bytes": 0, "name": "container"}]
This patch is for supporting last_modified key in the container
listing results as well as object listing like as:
[{"count": 0, "bytes": 0, "name": "container", "last_modified":
"2015-06-10T04:58:23.460230"}]
This patch is changing just output for listing. The original
timestamp to show the last modified is already in container table
of account.db as a "put_timestamp" column.
Note that this patch *DOESN'T* change the put_timestamp semantics.
i.e. the last_modified timestamp will be changed only at both PUT
container and POST container.
(PUT object doesn't affect the timestamp)
Note that the tuple format of returning value from
swift.account.backend.AccountBroker.list_containers is now
(name, object_count, bytes_used, put_timestamp, 0)
* put_timestamp is added *
Original discussion was in working session at Vancouver Summit.
Etherpads are around here:
https://etherpad.openstack.org/p/liberty-swift-contributors-meetup
https://etherpad.openstack.org/p/liberty-container-listing-update
DocImpact
Change-Id: Iba0503916f1481a20c59ae9136436f40183e4c5b
2014-12-15 20:45:41 -08:00
|
|
|
expected = [{'count': 2, 'bytes': 3, 'name': 'c0',
|
2017-01-12 18:04:40 +00:00
|
|
|
'last_modified': Timestamp('1').isoformat},
|
Support last modified on listing containers
For now, last modified timestamp is supported only on
object listing. (i.e. GET container)
For example:
GET container with json format results in like as:
[{"hash": "d41d8cd98f00b204e9800998ecf8427e", "last_modified":
"2015-06-10T04:58:23.460230", "bytes": 0, "name": "object",
"content_type": "application/octet-stream"}]
However, container listing (i.e. GET account) shows just a dict
consists of ("name", "bytes", "name") for each container.
For example:
GET accounts with json format result in like as:
[{"count": 0, "bytes": 0, "name": "container"}]
This patch is for supporting last_modified key in the container
listing results as well as object listing like as:
[{"count": 0, "bytes": 0, "name": "container", "last_modified":
"2015-06-10T04:58:23.460230"}]
This patch is changing just output for listing. The original
timestamp to show the last modified is already in container table
of account.db as a "put_timestamp" column.
Note that this patch *DOESN'T* change the put_timestamp semantics.
i.e. the last_modified timestamp will be changed only at both PUT
container and POST container.
(PUT object doesn't affect the timestamp)
Note that the tuple format of returning value from
swift.account.backend.AccountBroker.list_containers is now
(name, object_count, bytes_used, put_timestamp, 0)
* put_timestamp is added *
Original discussion was in working session at Vancouver Summit.
Etherpads are around here:
https://etherpad.openstack.org/p/liberty-swift-contributors-meetup
https://etherpad.openstack.org/p/liberty-container-listing-update
DocImpact
Change-Id: Iba0503916f1481a20c59ae9136436f40183e4c5b
2014-12-15 20:45:41 -08:00
|
|
|
{'count': 2, 'bytes': 3, 'name': 'c1',
|
2017-01-12 18:04:40 +00:00
|
|
|
'last_modified': Timestamp('2').isoformat},
|
Support last modified on listing containers
For now, last modified timestamp is supported only on
object listing. (i.e. GET container)
For example:
GET container with json format results in like as:
[{"hash": "d41d8cd98f00b204e9800998ecf8427e", "last_modified":
"2015-06-10T04:58:23.460230", "bytes": 0, "name": "object",
"content_type": "application/octet-stream"}]
However, container listing (i.e. GET account) shows just a dict
consists of ("name", "bytes", "name") for each container.
For example:
GET accounts with json format result in like as:
[{"count": 0, "bytes": 0, "name": "container"}]
This patch is for supporting last_modified key in the container
listing results as well as object listing like as:
[{"count": 0, "bytes": 0, "name": "container", "last_modified":
"2015-06-10T04:58:23.460230"}]
This patch is changing just output for listing. The original
timestamp to show the last modified is already in container table
of account.db as a "put_timestamp" column.
Note that this patch *DOESN'T* change the put_timestamp semantics.
i.e. the last_modified timestamp will be changed only at both PUT
container and POST container.
(PUT object doesn't affect the timestamp)
Note that the tuple format of returning value from
swift.account.backend.AccountBroker.list_containers is now
(name, object_count, bytes_used, put_timestamp, 0)
* put_timestamp is added *
Original discussion was in working session at Vancouver Summit.
Etherpads are around here:
https://etherpad.openstack.org/p/liberty-swift-contributors-meetup
https://etherpad.openstack.org/p/liberty-container-listing-update
DocImpact
Change-Id: Iba0503916f1481a20c59ae9136436f40183e4c5b
2014-12-15 20:45:41 -08:00
|
|
|
{'count': 2, 'bytes': 3, 'name': 'c2',
|
2017-01-12 18:04:40 +00:00
|
|
|
'last_modified': Timestamp('3').isoformat}]
|
Support last modified on listing containers
For now, last modified timestamp is supported only on
object listing. (i.e. GET container)
For example:
GET container with json format results in like as:
[{"hash": "d41d8cd98f00b204e9800998ecf8427e", "last_modified":
"2015-06-10T04:58:23.460230", "bytes": 0, "name": "object",
"content_type": "application/octet-stream"}]
However, container listing (i.e. GET account) shows just a dict
consists of ("name", "bytes", "name") for each container.
For example:
GET accounts with json format result in like as:
[{"count": 0, "bytes": 0, "name": "container"}]
This patch is for supporting last_modified key in the container
listing results as well as object listing like as:
[{"count": 0, "bytes": 0, "name": "container", "last_modified":
"2015-06-10T04:58:23.460230"}]
This patch is changing just output for listing. The original
timestamp to show the last modified is already in container table
of account.db as a "put_timestamp" column.
Note that this patch *DOESN'T* change the put_timestamp semantics.
i.e. the last_modified timestamp will be changed only at both PUT
container and POST container.
(PUT object doesn't affect the timestamp)
Note that the tuple format of returning value from
swift.account.backend.AccountBroker.list_containers is now
(name, object_count, bytes_used, put_timestamp, 0)
* put_timestamp is added *
Original discussion was in working session at Vancouver Summit.
Etherpads are around here:
https://etherpad.openstack.org/p/liberty-swift-contributors-meetup
https://etherpad.openstack.org/p/liberty-container-listing-update
DocImpact
Change-Id: Iba0503916f1481a20c59ae9136436f40183e4c5b
2014-12-15 20:45:41 -08:00
|
|
|
self.assertEqual(json.loads(resp.body), expected)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a?limit=3&marker=c2&format=json',
|
|
|
|
environ={'REQUEST_METHOD': 'GET'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 200)
|
Support last modified on listing containers
For now, last modified timestamp is supported only on
object listing. (i.e. GET container)
For example:
GET container with json format results in like as:
[{"hash": "d41d8cd98f00b204e9800998ecf8427e", "last_modified":
"2015-06-10T04:58:23.460230", "bytes": 0, "name": "object",
"content_type": "application/octet-stream"}]
However, container listing (i.e. GET account) shows just a dict
consists of ("name", "bytes", "name") for each container.
For example:
GET accounts with json format result in like as:
[{"count": 0, "bytes": 0, "name": "container"}]
This patch is for supporting last_modified key in the container
listing results as well as object listing like as:
[{"count": 0, "bytes": 0, "name": "container", "last_modified":
"2015-06-10T04:58:23.460230"}]
This patch is changing just output for listing. The original
timestamp to show the last modified is already in container table
of account.db as a "put_timestamp" column.
Note that this patch *DOESN'T* change the put_timestamp semantics.
i.e. the last_modified timestamp will be changed only at both PUT
container and POST container.
(PUT object doesn't affect the timestamp)
Note that the tuple format of returning value from
swift.account.backend.AccountBroker.list_containers is now
(name, object_count, bytes_used, put_timestamp, 0)
* put_timestamp is added *
Original discussion was in working session at Vancouver Summit.
Etherpads are around here:
https://etherpad.openstack.org/p/liberty-swift-contributors-meetup
https://etherpad.openstack.org/p/liberty-container-listing-update
DocImpact
Change-Id: Iba0503916f1481a20c59ae9136436f40183e4c5b
2014-12-15 20:45:41 -08:00
|
|
|
expected = [{'count': 2, 'bytes': 3, 'name': 'c3',
|
2017-01-12 18:04:40 +00:00
|
|
|
'last_modified': Timestamp('4').isoformat},
|
Support last modified on listing containers
For now, last modified timestamp is supported only on
object listing. (i.e. GET container)
For example:
GET container with json format results in like as:
[{"hash": "d41d8cd98f00b204e9800998ecf8427e", "last_modified":
"2015-06-10T04:58:23.460230", "bytes": 0, "name": "object",
"content_type": "application/octet-stream"}]
However, container listing (i.e. GET account) shows just a dict
consists of ("name", "bytes", "name") for each container.
For example:
GET accounts with json format result in like as:
[{"count": 0, "bytes": 0, "name": "container"}]
This patch is for supporting last_modified key in the container
listing results as well as object listing like as:
[{"count": 0, "bytes": 0, "name": "container", "last_modified":
"2015-06-10T04:58:23.460230"}]
This patch is changing just output for listing. The original
timestamp to show the last modified is already in container table
of account.db as a "put_timestamp" column.
Note that this patch *DOESN'T* change the put_timestamp semantics.
i.e. the last_modified timestamp will be changed only at both PUT
container and POST container.
(PUT object doesn't affect the timestamp)
Note that the tuple format of returning value from
swift.account.backend.AccountBroker.list_containers is now
(name, object_count, bytes_used, put_timestamp, 0)
* put_timestamp is added *
Original discussion was in working session at Vancouver Summit.
Etherpads are around here:
https://etherpad.openstack.org/p/liberty-swift-contributors-meetup
https://etherpad.openstack.org/p/liberty-container-listing-update
DocImpact
Change-Id: Iba0503916f1481a20c59ae9136436f40183e4c5b
2014-12-15 20:45:41 -08:00
|
|
|
{'count': 2, 'bytes': 3, 'name': 'c4',
|
2017-01-12 18:04:40 +00:00
|
|
|
'last_modified': Timestamp('5').isoformat}]
|
Support last modified on listing containers
For now, last modified timestamp is supported only on
object listing. (i.e. GET container)
For example:
GET container with json format results in like as:
[{"hash": "d41d8cd98f00b204e9800998ecf8427e", "last_modified":
"2015-06-10T04:58:23.460230", "bytes": 0, "name": "object",
"content_type": "application/octet-stream"}]
However, container listing (i.e. GET account) shows just a dict
consists of ("name", "bytes", "name") for each container.
For example:
GET accounts with json format result in like as:
[{"count": 0, "bytes": 0, "name": "container"}]
This patch is for supporting last_modified key in the container
listing results as well as object listing like as:
[{"count": 0, "bytes": 0, "name": "container", "last_modified":
"2015-06-10T04:58:23.460230"}]
This patch is changing just output for listing. The original
timestamp to show the last modified is already in container table
of account.db as a "put_timestamp" column.
Note that this patch *DOESN'T* change the put_timestamp semantics.
i.e. the last_modified timestamp will be changed only at both PUT
container and POST container.
(PUT object doesn't affect the timestamp)
Note that the tuple format of returning value from
swift.account.backend.AccountBroker.list_containers is now
(name, object_count, bytes_used, put_timestamp, 0)
* put_timestamp is added *
Original discussion was in working session at Vancouver Summit.
Etherpads are around here:
https://etherpad.openstack.org/p/liberty-swift-contributors-meetup
https://etherpad.openstack.org/p/liberty-container-listing-update
DocImpact
Change-Id: Iba0503916f1481a20c59ae9136436f40183e4c5b
2014-12-15 20:45:41 -08:00
|
|
|
self.assertEqual(json.loads(resp.body), expected)
|
2010-07-12 17:03:45 -05:00
|
|
|
|
|
|
|
def test_GET_limit_marker_xml(self):
|
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'PUT',
|
2013-09-01 01:54:03 -04:00
|
|
|
'HTTP_X_TIMESTAMP': '0'})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2015-05-25 18:28:02 +02:00
|
|
|
for c in range(5):
|
2017-01-12 17:44:10 -08:00
|
|
|
put_timestamp = normalize_timestamp(c + 1)
|
2013-09-01 01:54:03 -04:00
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a/c%d' % c,
|
|
|
|
environ={'REQUEST_METHOD': 'PUT'},
|
2017-01-12 17:44:10 -08:00
|
|
|
headers={'X-Put-Timestamp': put_timestamp,
|
2013-09-01 01:54:03 -04:00
|
|
|
'X-Delete-Timestamp': '0',
|
|
|
|
'X-Object-Count': '2',
|
|
|
|
'X-Bytes-Used': '3',
|
2017-01-12 17:44:10 -08:00
|
|
|
'X-Timestamp': put_timestamp})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a?limit=3&format=xml',
|
|
|
|
environ={'REQUEST_METHOD': 'GET'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 200)
|
2010-07-12 17:03:45 -05:00
|
|
|
dom = xml.dom.minidom.parseString(resp.body)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(dom.firstChild.nodeName, 'account')
|
2010-07-12 17:03:45 -05:00
|
|
|
listing = \
|
|
|
|
[n for n in dom.firstChild.childNodes if n.nodeName != '#text']
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(len(listing), 3)
|
|
|
|
self.assertEqual(listing[0].nodeName, 'container')
|
2010-07-12 17:03:45 -05:00
|
|
|
container = [n for n in listing[0].childNodes if n.nodeName != '#text']
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(sorted([n.nodeName for n in container]),
|
Support last modified on listing containers
For now, last modified timestamp is supported only on
object listing. (i.e. GET container)
For example:
GET container with json format results in like as:
[{"hash": "d41d8cd98f00b204e9800998ecf8427e", "last_modified":
"2015-06-10T04:58:23.460230", "bytes": 0, "name": "object",
"content_type": "application/octet-stream"}]
However, container listing (i.e. GET account) shows just a dict
consists of ("name", "bytes", "name") for each container.
For example:
GET accounts with json format result in like as:
[{"count": 0, "bytes": 0, "name": "container"}]
This patch is for supporting last_modified key in the container
listing results as well as object listing like as:
[{"count": 0, "bytes": 0, "name": "container", "last_modified":
"2015-06-10T04:58:23.460230"}]
This patch is changing just output for listing. The original
timestamp to show the last modified is already in container table
of account.db as a "put_timestamp" column.
Note that this patch *DOESN'T* change the put_timestamp semantics.
i.e. the last_modified timestamp will be changed only at both PUT
container and POST container.
(PUT object doesn't affect the timestamp)
Note that the tuple format of returning value from
swift.account.backend.AccountBroker.list_containers is now
(name, object_count, bytes_used, put_timestamp, 0)
* put_timestamp is added *
Original discussion was in working session at Vancouver Summit.
Etherpads are around here:
https://etherpad.openstack.org/p/liberty-swift-contributors-meetup
https://etherpad.openstack.org/p/liberty-container-listing-update
DocImpact
Change-Id: Iba0503916f1481a20c59ae9136436f40183e4c5b
2014-12-15 20:45:41 -08:00
|
|
|
['bytes', 'count', 'last_modified', 'name'])
|
2010-07-12 17:03:45 -05:00
|
|
|
node = [n for n in container if n.nodeName == 'name'][0]
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(node.firstChild.nodeValue, 'c0')
|
2010-07-12 17:03:45 -05:00
|
|
|
node = [n for n in container if n.nodeName == 'count'][0]
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(node.firstChild.nodeValue, '2')
|
2010-07-12 17:03:45 -05:00
|
|
|
node = [n for n in container if n.nodeName == 'bytes'][0]
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(node.firstChild.nodeValue, '3')
|
Support last modified on listing containers
For now, last modified timestamp is supported only on
object listing. (i.e. GET container)
For example:
GET container with json format results in like as:
[{"hash": "d41d8cd98f00b204e9800998ecf8427e", "last_modified":
"2015-06-10T04:58:23.460230", "bytes": 0, "name": "object",
"content_type": "application/octet-stream"}]
However, container listing (i.e. GET account) shows just a dict
consists of ("name", "bytes", "name") for each container.
For example:
GET accounts with json format result in like as:
[{"count": 0, "bytes": 0, "name": "container"}]
This patch is for supporting last_modified key in the container
listing results as well as object listing like as:
[{"count": 0, "bytes": 0, "name": "container", "last_modified":
"2015-06-10T04:58:23.460230"}]
This patch is changing just output for listing. The original
timestamp to show the last modified is already in container table
of account.db as a "put_timestamp" column.
Note that this patch *DOESN'T* change the put_timestamp semantics.
i.e. the last_modified timestamp will be changed only at both PUT
container and POST container.
(PUT object doesn't affect the timestamp)
Note that the tuple format of returning value from
swift.account.backend.AccountBroker.list_containers is now
(name, object_count, bytes_used, put_timestamp, 0)
* put_timestamp is added *
Original discussion was in working session at Vancouver Summit.
Etherpads are around here:
https://etherpad.openstack.org/p/liberty-swift-contributors-meetup
https://etherpad.openstack.org/p/liberty-container-listing-update
DocImpact
Change-Id: Iba0503916f1481a20c59ae9136436f40183e4c5b
2014-12-15 20:45:41 -08:00
|
|
|
node = [n for n in container if n.nodeName == 'last_modified'][0]
|
|
|
|
self.assertEqual(node.firstChild.nodeValue,
|
|
|
|
Timestamp('1').isoformat)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(listing[-1].nodeName, 'container')
|
2013-09-01 01:54:03 -04:00
|
|
|
container = [
|
|
|
|
n for n in listing[-1].childNodes if n.nodeName != '#text']
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(sorted([n.nodeName for n in container]),
|
Support last modified on listing containers
For now, last modified timestamp is supported only on
object listing. (i.e. GET container)
For example:
GET container with json format results in like as:
[{"hash": "d41d8cd98f00b204e9800998ecf8427e", "last_modified":
"2015-06-10T04:58:23.460230", "bytes": 0, "name": "object",
"content_type": "application/octet-stream"}]
However, container listing (i.e. GET account) shows just a dict
consists of ("name", "bytes", "name") for each container.
For example:
GET accounts with json format result in like as:
[{"count": 0, "bytes": 0, "name": "container"}]
This patch is for supporting last_modified key in the container
listing results as well as object listing like as:
[{"count": 0, "bytes": 0, "name": "container", "last_modified":
"2015-06-10T04:58:23.460230"}]
This patch is changing just output for listing. The original
timestamp to show the last modified is already in container table
of account.db as a "put_timestamp" column.
Note that this patch *DOESN'T* change the put_timestamp semantics.
i.e. the last_modified timestamp will be changed only at both PUT
container and POST container.
(PUT object doesn't affect the timestamp)
Note that the tuple format of returning value from
swift.account.backend.AccountBroker.list_containers is now
(name, object_count, bytes_used, put_timestamp, 0)
* put_timestamp is added *
Original discussion was in working session at Vancouver Summit.
Etherpads are around here:
https://etherpad.openstack.org/p/liberty-swift-contributors-meetup
https://etherpad.openstack.org/p/liberty-container-listing-update
DocImpact
Change-Id: Iba0503916f1481a20c59ae9136436f40183e4c5b
2014-12-15 20:45:41 -08:00
|
|
|
['bytes', 'count', 'last_modified', 'name'])
|
|
|
|
node = [n for n in container if n.nodeName == 'name'][0]
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(node.firstChild.nodeValue, 'c2')
|
2010-07-12 17:03:45 -05:00
|
|
|
node = [n for n in container if n.nodeName == 'count'][0]
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(node.firstChild.nodeValue, '2')
|
2010-07-12 17:03:45 -05:00
|
|
|
node = [n for n in container if n.nodeName == 'bytes'][0]
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(node.firstChild.nodeValue, '3')
|
Support last modified on listing containers
For now, last modified timestamp is supported only on
object listing. (i.e. GET container)
For example:
GET container with json format results in like as:
[{"hash": "d41d8cd98f00b204e9800998ecf8427e", "last_modified":
"2015-06-10T04:58:23.460230", "bytes": 0, "name": "object",
"content_type": "application/octet-stream"}]
However, container listing (i.e. GET account) shows just a dict
consists of ("name", "bytes", "name") for each container.
For example:
GET accounts with json format result in like as:
[{"count": 0, "bytes": 0, "name": "container"}]
This patch is for supporting last_modified key in the container
listing results as well as object listing like as:
[{"count": 0, "bytes": 0, "name": "container", "last_modified":
"2015-06-10T04:58:23.460230"}]
This patch is changing just output for listing. The original
timestamp to show the last modified is already in container table
of account.db as a "put_timestamp" column.
Note that this patch *DOESN'T* change the put_timestamp semantics.
i.e. the last_modified timestamp will be changed only at both PUT
container and POST container.
(PUT object doesn't affect the timestamp)
Note that the tuple format of returning value from
swift.account.backend.AccountBroker.list_containers is now
(name, object_count, bytes_used, put_timestamp, 0)
* put_timestamp is added *
Original discussion was in working session at Vancouver Summit.
Etherpads are around here:
https://etherpad.openstack.org/p/liberty-swift-contributors-meetup
https://etherpad.openstack.org/p/liberty-container-listing-update
DocImpact
Change-Id: Iba0503916f1481a20c59ae9136436f40183e4c5b
2014-12-15 20:45:41 -08:00
|
|
|
node = [n for n in container if n.nodeName == 'last_modified'][0]
|
|
|
|
self.assertEqual(node.firstChild.nodeValue,
|
|
|
|
Timestamp('3').isoformat)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a?limit=3&marker=c2&format=xml',
|
|
|
|
environ={'REQUEST_METHOD': 'GET'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 200)
|
2010-07-12 17:03:45 -05:00
|
|
|
dom = xml.dom.minidom.parseString(resp.body)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(dom.firstChild.nodeName, 'account')
|
2010-07-12 17:03:45 -05:00
|
|
|
listing = \
|
|
|
|
[n for n in dom.firstChild.childNodes if n.nodeName != '#text']
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(len(listing), 2)
|
|
|
|
self.assertEqual(listing[0].nodeName, 'container')
|
2010-07-12 17:03:45 -05:00
|
|
|
container = [n for n in listing[0].childNodes if n.nodeName != '#text']
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(sorted([n.nodeName for n in container]),
|
Support last modified on listing containers
For now, last modified timestamp is supported only on
object listing. (i.e. GET container)
For example:
GET container with json format results in like as:
[{"hash": "d41d8cd98f00b204e9800998ecf8427e", "last_modified":
"2015-06-10T04:58:23.460230", "bytes": 0, "name": "object",
"content_type": "application/octet-stream"}]
However, container listing (i.e. GET account) shows just a dict
consists of ("name", "bytes", "name") for each container.
For example:
GET accounts with json format result in like as:
[{"count": 0, "bytes": 0, "name": "container"}]
This patch is for supporting last_modified key in the container
listing results as well as object listing like as:
[{"count": 0, "bytes": 0, "name": "container", "last_modified":
"2015-06-10T04:58:23.460230"}]
This patch is changing just output for listing. The original
timestamp to show the last modified is already in container table
of account.db as a "put_timestamp" column.
Note that this patch *DOESN'T* change the put_timestamp semantics.
i.e. the last_modified timestamp will be changed only at both PUT
container and POST container.
(PUT object doesn't affect the timestamp)
Note that the tuple format of returning value from
swift.account.backend.AccountBroker.list_containers is now
(name, object_count, bytes_used, put_timestamp, 0)
* put_timestamp is added *
Original discussion was in working session at Vancouver Summit.
Etherpads are around here:
https://etherpad.openstack.org/p/liberty-swift-contributors-meetup
https://etherpad.openstack.org/p/liberty-container-listing-update
DocImpact
Change-Id: Iba0503916f1481a20c59ae9136436f40183e4c5b
2014-12-15 20:45:41 -08:00
|
|
|
['bytes', 'count', 'last_modified', 'name'])
|
2010-07-12 17:03:45 -05:00
|
|
|
node = [n for n in container if n.nodeName == 'name'][0]
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(node.firstChild.nodeValue, 'c3')
|
2010-07-12 17:03:45 -05:00
|
|
|
node = [n for n in container if n.nodeName == 'count'][0]
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(node.firstChild.nodeValue, '2')
|
2010-07-12 17:03:45 -05:00
|
|
|
node = [n for n in container if n.nodeName == 'bytes'][0]
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(node.firstChild.nodeValue, '3')
|
Support last modified on listing containers
For now, last modified timestamp is supported only on
object listing. (i.e. GET container)
For example:
GET container with json format results in like as:
[{"hash": "d41d8cd98f00b204e9800998ecf8427e", "last_modified":
"2015-06-10T04:58:23.460230", "bytes": 0, "name": "object",
"content_type": "application/octet-stream"}]
However, container listing (i.e. GET account) shows just a dict
consists of ("name", "bytes", "name") for each container.
For example:
GET accounts with json format result in like as:
[{"count": 0, "bytes": 0, "name": "container"}]
This patch is for supporting last_modified key in the container
listing results as well as object listing like as:
[{"count": 0, "bytes": 0, "name": "container", "last_modified":
"2015-06-10T04:58:23.460230"}]
This patch is changing just output for listing. The original
timestamp to show the last modified is already in container table
of account.db as a "put_timestamp" column.
Note that this patch *DOESN'T* change the put_timestamp semantics.
i.e. the last_modified timestamp will be changed only at both PUT
container and POST container.
(PUT object doesn't affect the timestamp)
Note that the tuple format of returning value from
swift.account.backend.AccountBroker.list_containers is now
(name, object_count, bytes_used, put_timestamp, 0)
* put_timestamp is added *
Original discussion was in working session at Vancouver Summit.
Etherpads are around here:
https://etherpad.openstack.org/p/liberty-swift-contributors-meetup
https://etherpad.openstack.org/p/liberty-container-listing-update
DocImpact
Change-Id: Iba0503916f1481a20c59ae9136436f40183e4c5b
2014-12-15 20:45:41 -08:00
|
|
|
node = [n for n in container if n.nodeName == 'last_modified'][0]
|
|
|
|
self.assertEqual(node.firstChild.nodeValue,
|
|
|
|
Timestamp('4').isoformat)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(listing[-1].nodeName, 'container')
|
2013-09-01 01:54:03 -04:00
|
|
|
container = [
|
|
|
|
n for n in listing[-1].childNodes if n.nodeName != '#text']
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(sorted([n.nodeName for n in container]),
|
Support last modified on listing containers
For now, last modified timestamp is supported only on
object listing. (i.e. GET container)
For example:
GET container with json format results in like as:
[{"hash": "d41d8cd98f00b204e9800998ecf8427e", "last_modified":
"2015-06-10T04:58:23.460230", "bytes": 0, "name": "object",
"content_type": "application/octet-stream"}]
However, container listing (i.e. GET account) shows just a dict
consists of ("name", "bytes", "name") for each container.
For example:
GET accounts with json format result in like as:
[{"count": 0, "bytes": 0, "name": "container"}]
This patch is for supporting last_modified key in the container
listing results as well as object listing like as:
[{"count": 0, "bytes": 0, "name": "container", "last_modified":
"2015-06-10T04:58:23.460230"}]
This patch is changing just output for listing. The original
timestamp to show the last modified is already in container table
of account.db as a "put_timestamp" column.
Note that this patch *DOESN'T* change the put_timestamp semantics.
i.e. the last_modified timestamp will be changed only at both PUT
container and POST container.
(PUT object doesn't affect the timestamp)
Note that the tuple format of returning value from
swift.account.backend.AccountBroker.list_containers is now
(name, object_count, bytes_used, put_timestamp, 0)
* put_timestamp is added *
Original discussion was in working session at Vancouver Summit.
Etherpads are around here:
https://etherpad.openstack.org/p/liberty-swift-contributors-meetup
https://etherpad.openstack.org/p/liberty-container-listing-update
DocImpact
Change-Id: Iba0503916f1481a20c59ae9136436f40183e4c5b
2014-12-15 20:45:41 -08:00
|
|
|
['bytes', 'count', 'last_modified', 'name'])
|
2010-07-12 17:03:45 -05:00
|
|
|
node = [n for n in container if n.nodeName == 'name'][0]
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(node.firstChild.nodeValue, 'c4')
|
2010-07-12 17:03:45 -05:00
|
|
|
node = [n for n in container if n.nodeName == 'count'][0]
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(node.firstChild.nodeValue, '2')
|
2010-07-12 17:03:45 -05:00
|
|
|
node = [n for n in container if n.nodeName == 'bytes'][0]
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(node.firstChild.nodeValue, '3')
|
2017-01-12 18:04:40 +00:00
|
|
|
node = [n for n in container if n.nodeName == 'last_modified'][0]
|
|
|
|
self.assertEqual(node.firstChild.nodeValue,
|
|
|
|
Timestamp('5').isoformat)
|
2010-07-12 17:03:45 -05:00
|
|
|
|
|
|
|
def test_GET_accept_wildcard(self):
|
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'PUT',
|
2013-09-01 01:54:03 -04:00
|
|
|
'HTTP_X_TIMESTAMP': '0'})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a/c1', environ={'REQUEST_METHOD': 'PUT'},
|
|
|
|
headers={'X-Put-Timestamp': '1',
|
|
|
|
'X-Delete-Timestamp': '0',
|
|
|
|
'X-Object-Count': '0',
|
|
|
|
'X-Bytes-Used': '0',
|
|
|
|
'X-Timestamp': normalize_timestamp(0)})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'GET'})
|
|
|
|
req.accept = '*/*'
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 200)
|
2018-10-23 00:57:50 -05:00
|
|
|
self.assertEqual(resp.body, b'c1\n')
|
2010-07-12 17:03:45 -05:00
|
|
|
|
|
|
|
def test_GET_accept_application_wildcard(self):
|
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'PUT',
|
2013-09-01 01:54:03 -04:00
|
|
|
'HTTP_X_TIMESTAMP': '0'})
|
2013-10-29 16:10:47 -06:00
|
|
|
resp = req.get_response(self.controller)
|
2015-08-05 22:25:46 +05:30
|
|
|
self.assertEqual(resp.status_int, 201)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a/c1', environ={'REQUEST_METHOD': 'PUT'},
|
|
|
|
headers={'X-Put-Timestamp': '1',
|
|
|
|
'X-Delete-Timestamp': '0',
|
|
|
|
'X-Object-Count': '0',
|
|
|
|
'X-Bytes-Used': '0',
|
|
|
|
'X-Timestamp': normalize_timestamp(0)})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2015-08-05 22:25:46 +05:30
|
|
|
self.assertEqual(resp.status_int, 201)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'GET'})
|
|
|
|
req.accept = 'application/*'
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 200)
|
2015-10-30 11:02:54 -07:00
|
|
|
self.assertEqual(len(json.loads(resp.body)), 1)
|
2010-07-12 17:03:45 -05:00
|
|
|
|
|
|
|
def test_GET_accept_json(self):
|
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'PUT',
|
2013-09-01 01:54:03 -04:00
|
|
|
'HTTP_X_TIMESTAMP': '0'})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a/c1', environ={'REQUEST_METHOD': 'PUT'},
|
|
|
|
headers={'X-Put-Timestamp': '1',
|
|
|
|
'X-Delete-Timestamp': '0',
|
|
|
|
'X-Object-Count': '0',
|
|
|
|
'X-Bytes-Used': '0',
|
|
|
|
'X-Timestamp': normalize_timestamp(0)})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'GET'})
|
|
|
|
req.accept = 'application/json'
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 200)
|
2015-10-30 11:02:54 -07:00
|
|
|
self.assertEqual(len(json.loads(resp.body)), 1)
|
2010-07-12 17:03:45 -05:00
|
|
|
|
|
|
|
def test_GET_accept_xml(self):
|
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'PUT',
|
2013-09-01 01:54:03 -04:00
|
|
|
'HTTP_X_TIMESTAMP': '0'})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a/c1', environ={'REQUEST_METHOD': 'PUT'},
|
|
|
|
headers={'X-Put-Timestamp': '1',
|
|
|
|
'X-Delete-Timestamp': '0',
|
|
|
|
'X-Object-Count': '0',
|
|
|
|
'X-Bytes-Used': '0',
|
|
|
|
'X-Timestamp': normalize_timestamp(0)})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'GET'})
|
|
|
|
req.accept = 'application/xml'
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 200)
|
2010-07-12 17:03:45 -05:00
|
|
|
dom = xml.dom.minidom.parseString(resp.body)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(dom.firstChild.nodeName, 'account')
|
2010-07-12 17:03:45 -05:00
|
|
|
listing = \
|
|
|
|
[n for n in dom.firstChild.childNodes if n.nodeName != '#text']
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(len(listing), 1)
|
2010-07-12 17:03:45 -05:00
|
|
|
|
|
|
|
def test_GET_accept_conflicting(self):
|
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'PUT',
|
2013-09-01 01:54:03 -04:00
|
|
|
'HTTP_X_TIMESTAMP': '0'})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a/c1', environ={'REQUEST_METHOD': 'PUT'},
|
|
|
|
headers={'X-Put-Timestamp': '1',
|
|
|
|
'X-Delete-Timestamp': '0',
|
|
|
|
'X-Object-Count': '0',
|
|
|
|
'X-Bytes-Used': '0',
|
|
|
|
'X-Timestamp': normalize_timestamp(0)})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2013-03-18 18:01:16 -07:00
|
|
|
req = Request.blank('/sda1/p/a?format=plain',
|
2010-07-12 17:03:45 -05:00
|
|
|
environ={'REQUEST_METHOD': 'GET'})
|
|
|
|
req.accept = 'application/json'
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 200)
|
2018-10-23 00:57:50 -05:00
|
|
|
self.assertEqual(resp.body, b'c1\n')
|
2010-07-12 17:03:45 -05:00
|
|
|
|
2011-11-16 13:48:23 -06:00
|
|
|
def test_GET_accept_not_valid(self):
|
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'PUT',
|
2013-09-01 01:54:03 -04:00
|
|
|
'HTTP_X_TIMESTAMP': '0'})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2011-11-16 13:48:23 -06:00
|
|
|
req = Request.blank('/sda1/p/a/c1', environ={'REQUEST_METHOD': 'PUT'},
|
|
|
|
headers={'X-Put-Timestamp': '1',
|
|
|
|
'X-Delete-Timestamp': '0',
|
|
|
|
'X-Object-Count': '0',
|
|
|
|
'X-Bytes-Used': '0',
|
|
|
|
'X-Timestamp': normalize_timestamp(0)})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2011-11-16 13:48:23 -06:00
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'GET'})
|
|
|
|
req.accept = 'application/xml*'
|
Refactor how we pick listings' content type.
There were a few different places where we had some repeated code to
figure out what format an account or container listing response should
be in (text, JSON, or XML). Now that's been pulled into a single
function.
As part of this, you can now raise HTTPException subclasses in proxy
controllers instead of laboriously plumbing error responses all the
way back up to swift.proxy.server.Application.handle_request(). This
lets us avoid certain ugly patterns, like the one where a method
returns a tuple of (x, y, z, error) and the caller has to see if it
got (value, value, value, None) or (None, None, None, errorvalue). Now
we can just raise the error.
Change-Id: I316873df289160d526487ad116f6fbb9a575e3de
2013-08-14 11:55:15 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 406)
|
2011-11-16 13:48:23 -06:00
|
|
|
|
2013-05-25 16:30:07 -04:00
|
|
|
def test_GET_prefix_delimiter_plain(self):
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'PUT',
|
2013-09-01 01:54:03 -04:00
|
|
|
'HTTP_X_TIMESTAMP': '0'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2010-07-12 17:03:45 -05:00
|
|
|
for first in range(3):
|
2013-09-01 01:54:03 -04:00
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a/sub.%s' % first,
|
2010-07-12 17:03:45 -05:00
|
|
|
environ={'REQUEST_METHOD': 'PUT'},
|
|
|
|
headers={'X-Put-Timestamp': '1',
|
|
|
|
'X-Delete-Timestamp': '0',
|
|
|
|
'X-Object-Count': '0',
|
|
|
|
'X-Bytes-Used': '0',
|
|
|
|
'X-Timestamp': normalize_timestamp(0)})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2010-07-12 17:03:45 -05:00
|
|
|
for second in range(3):
|
2013-09-01 01:54:03 -04:00
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a/sub.%s.%s' % (first, second),
|
2010-07-12 17:03:45 -05:00
|
|
|
environ={'REQUEST_METHOD': 'PUT'},
|
|
|
|
headers={'X-Put-Timestamp': '1',
|
|
|
|
'X-Delete-Timestamp': '0',
|
|
|
|
'X-Object-Count': '0',
|
|
|
|
'X-Bytes-Used': '0',
|
|
|
|
'X-Timestamp': normalize_timestamp(0)})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a?delimiter=.',
|
2013-09-01 01:54:03 -04:00
|
|
|
environ={'REQUEST_METHOD': 'GET'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 200)
|
2018-12-27 23:01:52 +00:00
|
|
|
self.assertEqual(resp.body.strip().split(b'\n'),
|
|
|
|
[b'sub.'])
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a?prefix=sub.&delimiter=.',
|
2013-09-01 01:54:03 -04:00
|
|
|
environ={'REQUEST_METHOD': 'GET'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 200)
|
|
|
|
self.assertEqual(
|
2018-12-27 23:01:52 +00:00
|
|
|
resp.body.strip().split(b'\n'),
|
|
|
|
[b'sub.0', b'sub.0.', b'sub.1', b'sub.1.', b'sub.2', b'sub.2.'])
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a?prefix=sub.1.&delimiter=.',
|
2013-09-01 01:54:03 -04:00
|
|
|
environ={'REQUEST_METHOD': 'GET'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 200)
|
2018-12-27 23:01:52 +00:00
|
|
|
self.assertEqual(resp.body.strip().split(b'\n'),
|
|
|
|
[b'sub.1.0', b'sub.1.1', b'sub.1.2'])
|
2010-07-12 17:03:45 -05:00
|
|
|
|
2013-05-25 16:30:07 -04:00
|
|
|
def test_GET_prefix_delimiter_json(self):
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'PUT',
|
2013-09-01 01:54:03 -04:00
|
|
|
'HTTP_X_TIMESTAMP': '0'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2010-07-12 17:03:45 -05:00
|
|
|
for first in range(3):
|
2013-09-01 01:54:03 -04:00
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a/sub.%s' % first,
|
2010-07-12 17:03:45 -05:00
|
|
|
environ={'REQUEST_METHOD': 'PUT'},
|
|
|
|
headers={'X-Put-Timestamp': '1',
|
|
|
|
'X-Delete-Timestamp': '0',
|
|
|
|
'X-Object-Count': '0',
|
|
|
|
'X-Bytes-Used': '0',
|
|
|
|
'X-Timestamp': normalize_timestamp(0)})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2010-07-12 17:03:45 -05:00
|
|
|
for second in range(3):
|
2013-09-01 01:54:03 -04:00
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a/sub.%s.%s' % (first, second),
|
2010-07-12 17:03:45 -05:00
|
|
|
environ={'REQUEST_METHOD': 'PUT'},
|
|
|
|
headers={'X-Put-Timestamp': '1',
|
|
|
|
'X-Delete-Timestamp': '0',
|
|
|
|
'X-Object-Count': '0',
|
|
|
|
'X-Bytes-Used': '0',
|
|
|
|
'X-Timestamp': normalize_timestamp(0)})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a?delimiter=.&format=json',
|
2013-09-01 01:54:03 -04:00
|
|
|
environ={'REQUEST_METHOD': 'GET'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 200)
|
|
|
|
self.assertEqual([n.get('name', 's:' + n.get('subdir', 'error'))
|
2015-10-30 11:02:54 -07:00
|
|
|
for n in json.loads(resp.body)], ['s:sub.'])
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a?prefix=sub.&delimiter=.&format=json',
|
2013-09-01 01:54:03 -04:00
|
|
|
environ={'REQUEST_METHOD': 'GET'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 200)
|
|
|
|
self.assertEqual(
|
2013-09-01 01:54:03 -04:00
|
|
|
[n.get('name', 's:' + n.get('subdir', 'error'))
|
2015-10-30 11:02:54 -07:00
|
|
|
for n in json.loads(resp.body)],
|
2010-07-12 17:03:45 -05:00
|
|
|
['sub.0', 's:sub.0.', 'sub.1', 's:sub.1.', 'sub.2', 's:sub.2.'])
|
|
|
|
req = Request.blank('/sda1/p/a?prefix=sub.1.&delimiter=.&format=json',
|
2013-09-01 01:54:03 -04:00
|
|
|
environ={'REQUEST_METHOD': 'GET'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 200)
|
|
|
|
self.assertEqual(
|
2013-09-01 01:54:03 -04:00
|
|
|
[n.get('name', 's:' + n.get('subdir', 'error'))
|
2015-10-30 11:02:54 -07:00
|
|
|
for n in json.loads(resp.body)],
|
2010-07-12 17:03:45 -05:00
|
|
|
['sub.1.0', 'sub.1.1', 'sub.1.2'])
|
|
|
|
|
2013-05-25 16:30:07 -04:00
|
|
|
def test_GET_prefix_delimiter_xml(self):
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'PUT',
|
2013-09-01 01:54:03 -04:00
|
|
|
'HTTP_X_TIMESTAMP': '0'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2010-07-12 17:03:45 -05:00
|
|
|
for first in range(3):
|
2013-09-01 01:54:03 -04:00
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a/sub.%s' % first,
|
2010-07-12 17:03:45 -05:00
|
|
|
environ={'REQUEST_METHOD': 'PUT'},
|
|
|
|
headers={'X-Put-Timestamp': '1',
|
|
|
|
'X-Delete-Timestamp': '0',
|
|
|
|
'X-Object-Count': '0',
|
|
|
|
'X-Bytes-Used': '0',
|
|
|
|
'X-Timestamp': normalize_timestamp(0)})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2010-07-12 17:03:45 -05:00
|
|
|
for second in range(3):
|
2013-09-01 01:54:03 -04:00
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a/sub.%s.%s' % (first, second),
|
2010-07-12 17:03:45 -05:00
|
|
|
environ={'REQUEST_METHOD': 'PUT'},
|
|
|
|
headers={'X-Put-Timestamp': '1',
|
|
|
|
'X-Delete-Timestamp': '0',
|
|
|
|
'X-Object-Count': '0',
|
|
|
|
'X-Bytes-Used': '0',
|
|
|
|
'X-Timestamp': normalize_timestamp(0)})
|
2013-08-16 16:24:00 -07:00
|
|
|
req.get_response(self.controller)
|
2013-09-01 01:54:03 -04:00
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a?delimiter=.&format=xml',
|
2010-07-12 17:03:45 -05:00
|
|
|
environ={'REQUEST_METHOD': 'GET'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 200)
|
2010-07-12 17:03:45 -05:00
|
|
|
dom = xml.dom.minidom.parseString(resp.body)
|
|
|
|
listing = []
|
|
|
|
for node1 in dom.firstChild.childNodes:
|
|
|
|
if node1.nodeName == 'subdir':
|
|
|
|
listing.append('s:' + node1.attributes['name'].value)
|
|
|
|
elif node1.nodeName == 'container':
|
|
|
|
for node2 in node1.childNodes:
|
|
|
|
if node2.nodeName == 'name':
|
|
|
|
listing.append(node2.firstChild.nodeValue)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(listing, ['s:sub.'])
|
2013-09-01 01:54:03 -04:00
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a?prefix=sub.&delimiter=.&format=xml',
|
2010-07-12 17:03:45 -05:00
|
|
|
environ={'REQUEST_METHOD': 'GET'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 200)
|
2010-07-12 17:03:45 -05:00
|
|
|
dom = xml.dom.minidom.parseString(resp.body)
|
|
|
|
listing = []
|
|
|
|
for node1 in dom.firstChild.childNodes:
|
|
|
|
if node1.nodeName == 'subdir':
|
|
|
|
listing.append('s:' + node1.attributes['name'].value)
|
|
|
|
elif node1.nodeName == 'container':
|
|
|
|
for node2 in node1.childNodes:
|
|
|
|
if node2.nodeName == 'name':
|
|
|
|
listing.append(node2.firstChild.nodeValue)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(
|
2013-09-01 01:54:03 -04:00
|
|
|
listing,
|
2010-07-12 17:03:45 -05:00
|
|
|
['sub.0', 's:sub.0.', 'sub.1', 's:sub.1.', 'sub.2', 's:sub.2.'])
|
2013-09-01 01:54:03 -04:00
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a?prefix=sub.1.&delimiter=.&format=xml',
|
2010-07-12 17:03:45 -05:00
|
|
|
environ={'REQUEST_METHOD': 'GET'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 200)
|
2010-07-12 17:03:45 -05:00
|
|
|
dom = xml.dom.minidom.parseString(resp.body)
|
|
|
|
listing = []
|
|
|
|
for node1 in dom.firstChild.childNodes:
|
|
|
|
if node1.nodeName == 'subdir':
|
|
|
|
listing.append('s:' + node1.attributes['name'].value)
|
|
|
|
elif node1.nodeName == 'container':
|
|
|
|
for node2 in node1.childNodes:
|
|
|
|
if node2.nodeName == 'name':
|
|
|
|
listing.append(node2.firstChild.nodeValue)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(listing, ['sub.1.0', 'sub.1.1', 'sub.1.2'])
|
2010-07-12 17:03:45 -05:00
|
|
|
|
2020-01-02 16:21:19 -08:00
|
|
|
def test_GET_leading_delimiter(self):
|
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'PUT',
|
|
|
|
'HTTP_X_TIMESTAMP': '0'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
for first in range(3):
|
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a/.sub.%s' % first,
|
|
|
|
environ={'REQUEST_METHOD': 'PUT'},
|
|
|
|
headers={'X-Put-Timestamp': '1',
|
|
|
|
'X-Delete-Timestamp': '0',
|
|
|
|
'X-Object-Count': '0',
|
|
|
|
'X-Bytes-Used': '0',
|
|
|
|
'X-Timestamp': normalize_timestamp(0)})
|
|
|
|
req.get_response(self.controller)
|
|
|
|
for second in range(3):
|
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a/.sub.%s.%s' % (first, second),
|
|
|
|
environ={'REQUEST_METHOD': 'PUT'},
|
|
|
|
headers={'X-Put-Timestamp': '1',
|
|
|
|
'X-Delete-Timestamp': '0',
|
|
|
|
'X-Object-Count': '0',
|
|
|
|
'X-Bytes-Used': '0',
|
|
|
|
'X-Timestamp': normalize_timestamp(0)})
|
|
|
|
req.get_response(self.controller)
|
|
|
|
req = Request.blank('/sda1/p/a?delimiter=.',
|
|
|
|
environ={'REQUEST_METHOD': 'GET'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 200)
|
|
|
|
self.assertEqual(resp.body.strip().split(b'\n'),
|
|
|
|
[b'.'])
|
|
|
|
req = Request.blank('/sda1/p/a?prefix=.&delimiter=.',
|
|
|
|
environ={'REQUEST_METHOD': 'GET'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 200)
|
|
|
|
self.assertEqual(resp.body.strip().split(b'\n'),
|
|
|
|
[b'.sub.'])
|
|
|
|
req = Request.blank('/sda1/p/a?prefix=.sub.&delimiter=.',
|
|
|
|
environ={'REQUEST_METHOD': 'GET'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 200)
|
|
|
|
self.assertEqual(
|
|
|
|
resp.body.strip().split(b'\n'),
|
|
|
|
[b'.sub.0', b'.sub.0.', b'.sub.1', b'.sub.1.',
|
|
|
|
b'.sub.2', b'.sub.2.'])
|
|
|
|
req = Request.blank('/sda1/p/a?prefix=.sub.1.&delimiter=.',
|
|
|
|
environ={'REQUEST_METHOD': 'GET'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 200)
|
|
|
|
self.assertEqual(resp.body.strip().split(b'\n'),
|
|
|
|
[b'.sub.1.0', b'.sub.1.1', b'.sub.1.2'])
|
|
|
|
|
2018-10-11 15:23:39 -07:00
|
|
|
def test_GET_multichar_delimiter(self):
|
|
|
|
self.maxDiff = None
|
|
|
|
req = Request.blank('/sda1/p/a', method='PUT', headers={
|
|
|
|
'x-timestamp': '0'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 201, resp.body)
|
|
|
|
for i in ('US~~TX~~A', 'US~~TX~~B', 'US~~OK~~A', 'US~~OK~~B',
|
|
|
|
'US~~OK~Tulsa~~A', 'US~~OK~Tulsa~~B',
|
|
|
|
'US~~UT~~A', 'US~~UT~~~B'):
|
|
|
|
req = Request.blank('/sda1/p/a/%s' % i, method='PUT', headers={
|
|
|
|
'X-Put-Timestamp': '1',
|
|
|
|
'X-Delete-Timestamp': '0',
|
|
|
|
'X-Object-Count': '0',
|
|
|
|
'X-Bytes-Used': '0',
|
|
|
|
'X-Timestamp': normalize_timestamp(0)})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 201)
|
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a?prefix=US~~&delimiter=~~&format=json',
|
|
|
|
environ={'REQUEST_METHOD': 'GET'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(
|
|
|
|
json.loads(resp.body),
|
|
|
|
[{"subdir": "US~~OK~Tulsa~~"},
|
|
|
|
{"subdir": "US~~OK~~"},
|
|
|
|
{"subdir": "US~~TX~~"},
|
|
|
|
{"subdir": "US~~UT~~"}])
|
|
|
|
|
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a?prefix=US~~&delimiter=~~&format=json&reverse=on',
|
|
|
|
environ={'REQUEST_METHOD': 'GET'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(
|
|
|
|
json.loads(resp.body),
|
|
|
|
[{"subdir": "US~~UT~~"},
|
|
|
|
{"subdir": "US~~TX~~"},
|
|
|
|
{"subdir": "US~~OK~~"},
|
|
|
|
{"subdir": "US~~OK~Tulsa~~"}])
|
|
|
|
|
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a?prefix=US~~UT&delimiter=~~&format=json',
|
|
|
|
environ={'REQUEST_METHOD': 'GET'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(
|
|
|
|
json.loads(resp.body),
|
|
|
|
[{"subdir": "US~~UT~~"}])
|
|
|
|
|
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a?prefix=US~~UT&delimiter=~~&format=json&reverse=on',
|
|
|
|
environ={'REQUEST_METHOD': 'GET'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(
|
|
|
|
json.loads(resp.body),
|
|
|
|
[{"subdir": "US~~UT~~"}])
|
|
|
|
|
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a?prefix=US~~UT~&delimiter=~~&format=json',
|
|
|
|
environ={'REQUEST_METHOD': 'GET'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(
|
|
|
|
[{k: v for k, v in item.items() if k in ('subdir', 'name')}
|
|
|
|
for item in json.loads(resp.body)],
|
|
|
|
[{"name": "US~~UT~~A"},
|
|
|
|
{"subdir": "US~~UT~~~"}])
|
|
|
|
|
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a?prefix=US~~UT~&delimiter=~~&format=json&reverse=on',
|
|
|
|
environ={'REQUEST_METHOD': 'GET'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(
|
|
|
|
[{k: v for k, v in item.items() if k in ('subdir', 'name')}
|
|
|
|
for item in json.loads(resp.body)],
|
|
|
|
[{"subdir": "US~~UT~~~"},
|
|
|
|
{"name": "US~~UT~~A"}])
|
|
|
|
|
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a?prefix=US~~UT~~&delimiter=~~&format=json',
|
|
|
|
environ={'REQUEST_METHOD': 'GET'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(
|
|
|
|
[{k: v for k, v in item.items() if k in ('subdir', 'name')}
|
|
|
|
for item in json.loads(resp.body)],
|
|
|
|
[{"name": "US~~UT~~A"},
|
|
|
|
{"name": "US~~UT~~~B"}])
|
|
|
|
|
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a?prefix=US~~UT~~&delimiter=~~&format=json&reverse=on',
|
|
|
|
environ={'REQUEST_METHOD': 'GET'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(
|
|
|
|
[{k: v for k, v in item.items() if k in ('subdir', 'name')}
|
|
|
|
for item in json.loads(resp.body)],
|
|
|
|
[{"name": "US~~UT~~~B"},
|
|
|
|
{"name": "US~~UT~~A"}])
|
|
|
|
|
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a?prefix=US~~UT~~~&delimiter=~~&format=json',
|
|
|
|
environ={'REQUEST_METHOD': 'GET'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(
|
|
|
|
[{k: v for k, v in item.items() if k in ('subdir', 'name')}
|
|
|
|
for item in json.loads(resp.body)],
|
|
|
|
[{"name": "US~~UT~~~B"}])
|
|
|
|
|
2019-09-13 12:25:24 -05:00
|
|
|
def _expected_listing(self, containers):
|
|
|
|
return [dict(
|
|
|
|
last_modified=c['timestamp'].isoformat, **{
|
|
|
|
k: v for k, v in c.items()
|
|
|
|
if k != 'timestamp'
|
|
|
|
}) for c in sorted(containers, key=lambda c: c['name'])]
|
|
|
|
|
|
|
|
def _report_containers(self, containers, account='a'):
|
|
|
|
req = Request.blank('/sda1/p/%s' % account, method='PUT', headers={
|
|
|
|
'x-timestamp': next(self.ts).internal})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int // 100, 2, resp.body)
|
|
|
|
for container in containers:
|
|
|
|
path = '/sda1/p/%s/%s' % (account, container['name'])
|
|
|
|
req = Request.blank(path, method='PUT', headers={
|
|
|
|
'X-Put-Timestamp': container['timestamp'].internal,
|
|
|
|
'X-Delete-Timestamp': container.get(
|
|
|
|
'deleted', Timestamp(0)).internal,
|
|
|
|
'X-Object-Count': container['count'],
|
|
|
|
'X-Bytes-Used': container['bytes'],
|
|
|
|
})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int // 100, 2, resp.body)
|
|
|
|
|
|
|
|
def test_delimiter_with_reserved_and_no_public(self):
|
|
|
|
containers = [{
|
|
|
|
'name': get_reserved_name('null', 'test01'),
|
|
|
|
'bytes': 200,
|
|
|
|
'count': 2,
|
|
|
|
'timestamp': next(self.ts),
|
|
|
|
}]
|
|
|
|
self._report_containers(containers)
|
|
|
|
|
|
|
|
req = Request.blank('/sda1/p/a', headers={
|
|
|
|
'Accept': 'application/json'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 200, resp.body)
|
|
|
|
self.assertEqual(json.loads(resp.body), [])
|
|
|
|
|
|
|
|
req = Request.blank('/sda1/p/a', headers={
|
|
|
|
'X-Backend-Allow-Reserved-Names': 'true',
|
|
|
|
'Accept': 'application/json'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 200, resp.body)
|
|
|
|
self.assertEqual(json.loads(resp.body),
|
|
|
|
self._expected_listing(containers))
|
|
|
|
|
|
|
|
req = Request.blank('/sda1/p/a?prefix=%s&delimiter=l' %
|
|
|
|
get_reserved_name('nul'), headers={
|
|
|
|
'Accept': 'application/json'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 200, resp.body)
|
|
|
|
self.assertEqual(json.loads(resp.body), [])
|
|
|
|
|
|
|
|
req = Request.blank('/sda1/p/a?prefix=%s&delimiter=l' %
|
|
|
|
get_reserved_name('nul'), headers={
|
|
|
|
'X-Backend-Allow-Reserved-Names': 'true',
|
|
|
|
'Accept': 'application/json'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 200, resp.body)
|
|
|
|
self.assertEqual(json.loads(resp.body), [{
|
|
|
|
'subdir': '%s' % get_reserved_name('null')}])
|
|
|
|
|
|
|
|
def test_delimiter_with_reserved_and_public(self):
|
|
|
|
containers = [{
|
|
|
|
'name': get_reserved_name('null', 'test01'),
|
|
|
|
'bytes': 200,
|
|
|
|
'count': 2,
|
|
|
|
'timestamp': next(self.ts),
|
|
|
|
}, {
|
|
|
|
'name': 'nullish',
|
|
|
|
'bytes': 10,
|
|
|
|
'count': 10,
|
|
|
|
'timestamp': next(self.ts),
|
|
|
|
}]
|
|
|
|
self._report_containers(containers)
|
|
|
|
|
|
|
|
req = Request.blank('/sda1/p/a?prefix=nul&delimiter=l', headers={
|
|
|
|
'Accept': 'application/json'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 200, resp.body)
|
|
|
|
self.assertEqual(json.loads(resp.body), [{'subdir': 'null'}])
|
|
|
|
|
|
|
|
# allow-reserved header doesn't really make a difference
|
|
|
|
req = Request.blank('/sda1/p/a?prefix=nul&delimiter=l', headers={
|
|
|
|
'X-Backend-Allow-Reserved-Names': 'true',
|
|
|
|
'Accept': 'application/json'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 200, resp.body)
|
|
|
|
self.assertEqual(json.loads(resp.body), [{'subdir': 'null'}])
|
|
|
|
|
|
|
|
req = Request.blank('/sda1/p/a?prefix=%s&delimiter=l' %
|
|
|
|
get_reserved_name('nul'), headers={
|
|
|
|
'Accept': 'application/json'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 200, resp.body)
|
|
|
|
self.assertEqual(json.loads(resp.body), [])
|
|
|
|
|
|
|
|
req = Request.blank('/sda1/p/a?prefix=%s&delimiter=l' %
|
|
|
|
get_reserved_name('nul'), headers={
|
|
|
|
'X-Backend-Allow-Reserved-Names': 'true',
|
|
|
|
'Accept': 'application/json'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 200, resp.body)
|
|
|
|
self.assertEqual(json.loads(resp.body), [{
|
|
|
|
'subdir': '%s' % get_reserved_name('null')}])
|
|
|
|
|
|
|
|
req = Request.blank('/sda1/p/a?delimiter=%00', headers={
|
|
|
|
'Accept': 'application/json'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 200, resp.body)
|
|
|
|
self.assertEqual(json.loads(resp.body),
|
|
|
|
self._expected_listing(containers)[1:])
|
|
|
|
|
|
|
|
req = Request.blank('/sda1/p/a?delimiter=%00', headers={
|
|
|
|
'X-Backend-Allow-Reserved-Names': 'true',
|
|
|
|
'Accept': 'application/json'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 200, resp.body)
|
|
|
|
self.assertEqual(json.loads(resp.body),
|
|
|
|
[{'subdir': '\x00'}] +
|
|
|
|
self._expected_listing(containers)[1:])
|
|
|
|
|
|
|
|
def test_markers_with_reserved(self):
|
|
|
|
containers = [{
|
|
|
|
'name': get_reserved_name('null', 'test01'),
|
|
|
|
'bytes': 200,
|
|
|
|
'count': 2,
|
|
|
|
'timestamp': next(self.ts),
|
|
|
|
}, {
|
|
|
|
'name': get_reserved_name('null', 'test02'),
|
|
|
|
'bytes': 10,
|
|
|
|
'count': 10,
|
|
|
|
'timestamp': next(self.ts),
|
|
|
|
}]
|
|
|
|
self._report_containers(containers)
|
|
|
|
|
|
|
|
req = Request.blank('/sda1/p/a?marker=%s' %
|
|
|
|
get_reserved_name('null', ''), headers={
|
|
|
|
'Accept': 'application/json'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 200, resp.body)
|
|
|
|
self.assertEqual(json.loads(resp.body), [])
|
|
|
|
|
|
|
|
req = Request.blank('/sda1/p/a?marker=%s' %
|
|
|
|
get_reserved_name('null', ''), headers={
|
|
|
|
'X-Backend-Allow-Reserved-Names': 'true',
|
|
|
|
'Accept': 'application/json'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 200, resp.body)
|
|
|
|
self.assertEqual(json.loads(resp.body),
|
|
|
|
self._expected_listing(containers))
|
|
|
|
|
|
|
|
req = Request.blank('/sda1/p/a?marker=%s' % quote(
|
|
|
|
self._expected_listing(containers)[0]['name']), headers={
|
|
|
|
'X-Backend-Allow-Reserved-Names': 'true',
|
|
|
|
'Accept': 'application/json'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 200, resp.body)
|
|
|
|
self.assertEqual(json.loads(resp.body),
|
|
|
|
self._expected_listing(containers)[1:])
|
|
|
|
|
|
|
|
containers.append({
|
|
|
|
'name': get_reserved_name('null', 'test03'),
|
|
|
|
'bytes': 300,
|
|
|
|
'count': 30,
|
|
|
|
'timestamp': next(self.ts),
|
|
|
|
})
|
|
|
|
self._report_containers(containers)
|
|
|
|
|
|
|
|
req = Request.blank('/sda1/p/a?marker=%s' % quote(
|
|
|
|
self._expected_listing(containers)[0]['name']), headers={
|
|
|
|
'X-Backend-Allow-Reserved-Names': 'true',
|
|
|
|
'Accept': 'application/json'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 200, resp.body)
|
|
|
|
self.assertEqual(json.loads(resp.body),
|
|
|
|
self._expected_listing(containers)[1:])
|
|
|
|
|
|
|
|
req = Request.blank('/sda1/p/a?marker=%s' % quote(
|
|
|
|
self._expected_listing(containers)[1]['name']), headers={
|
|
|
|
'X-Backend-Allow-Reserved-Names': 'true',
|
|
|
|
'Accept': 'application/json'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 200, resp.body)
|
|
|
|
self.assertEqual(json.loads(resp.body),
|
|
|
|
self._expected_listing(containers)[-1:])
|
|
|
|
|
|
|
|
def test_prefix_with_reserved(self):
|
|
|
|
containers = [{
|
|
|
|
'name': get_reserved_name('null', 'test01'),
|
|
|
|
'bytes': 200,
|
|
|
|
'count': 2,
|
|
|
|
'timestamp': next(self.ts),
|
|
|
|
}, {
|
|
|
|
'name': get_reserved_name('null', 'test02'),
|
|
|
|
'bytes': 10,
|
|
|
|
'count': 10,
|
|
|
|
'timestamp': next(self.ts),
|
|
|
|
}, {
|
|
|
|
'name': get_reserved_name('null', 'foo'),
|
|
|
|
'bytes': 10,
|
|
|
|
'count': 10,
|
|
|
|
'timestamp': next(self.ts),
|
|
|
|
}, {
|
|
|
|
'name': get_reserved_name('nullish'),
|
|
|
|
'bytes': 300,
|
|
|
|
'count': 32,
|
|
|
|
'timestamp': next(self.ts),
|
|
|
|
}]
|
|
|
|
self._report_containers(containers)
|
|
|
|
|
|
|
|
req = Request.blank('/sda1/p/a?prefix=%s' %
|
|
|
|
get_reserved_name('null', 'test'), headers={
|
|
|
|
'Accept': 'application/json'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 200, resp.body)
|
|
|
|
self.assertEqual(json.loads(resp.body), [])
|
|
|
|
|
|
|
|
req = Request.blank('/sda1/p/a?prefix=%s' %
|
|
|
|
get_reserved_name('null', 'test'), headers={
|
|
|
|
'X-Backend-Allow-Reserved-Names': 'true',
|
|
|
|
'Accept': 'application/json'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 200, resp.body)
|
|
|
|
self.assertEqual(json.loads(resp.body),
|
|
|
|
self._expected_listing(containers[:2]))
|
|
|
|
|
|
|
|
def test_prefix_and_delim_with_reserved(self):
|
|
|
|
containers = [{
|
|
|
|
'name': get_reserved_name('null', 'test01'),
|
|
|
|
'bytes': 200,
|
|
|
|
'count': 2,
|
|
|
|
'timestamp': next(self.ts),
|
|
|
|
}, {
|
|
|
|
'name': get_reserved_name('null', 'test02'),
|
|
|
|
'bytes': 10,
|
|
|
|
'count': 10,
|
|
|
|
'timestamp': next(self.ts),
|
|
|
|
}, {
|
|
|
|
'name': get_reserved_name('null', 'foo'),
|
|
|
|
'bytes': 10,
|
|
|
|
'count': 10,
|
|
|
|
'timestamp': next(self.ts),
|
|
|
|
}, {
|
|
|
|
'name': get_reserved_name('nullish'),
|
|
|
|
'bytes': 300,
|
|
|
|
'count': 32,
|
|
|
|
'timestamp': next(self.ts),
|
|
|
|
}]
|
|
|
|
self._report_containers(containers)
|
|
|
|
|
|
|
|
req = Request.blank('/sda1/p/a?prefix=%s&delimiter=%s' % (
|
|
|
|
get_reserved_name('null'), get_reserved_name()), headers={
|
|
|
|
'Accept': 'application/json'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 200, resp.body)
|
|
|
|
self.assertEqual(json.loads(resp.body), [])
|
|
|
|
|
|
|
|
req = Request.blank('/sda1/p/a?prefix=%s&delimiter=%s' % (
|
|
|
|
get_reserved_name('null'), get_reserved_name()), headers={
|
|
|
|
'X-Backend-Allow-Reserved-Names': 'true',
|
|
|
|
'Accept': 'application/json'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 200, resp.body)
|
|
|
|
expected = [{'subdir': get_reserved_name('null', '')}] + \
|
|
|
|
self._expected_listing(containers[-1:])
|
|
|
|
self.assertEqual(json.loads(resp.body), expected)
|
|
|
|
|
|
|
|
def test_reserved_markers_with_non_reserved(self):
|
|
|
|
containers = [{
|
|
|
|
'name': get_reserved_name('null', 'test01'),
|
|
|
|
'bytes': 200,
|
|
|
|
'count': 2,
|
|
|
|
'timestamp': next(self.ts),
|
|
|
|
}, {
|
|
|
|
'name': get_reserved_name('null', 'test02'),
|
|
|
|
'bytes': 10,
|
|
|
|
'count': 10,
|
|
|
|
'timestamp': next(self.ts),
|
|
|
|
}, {
|
|
|
|
'name': 'nullish',
|
|
|
|
'bytes': 300,
|
|
|
|
'count': 32,
|
|
|
|
'timestamp': next(self.ts),
|
|
|
|
}]
|
|
|
|
self._report_containers(containers)
|
|
|
|
|
|
|
|
req = Request.blank('/sda1/p/a?marker=%s' %
|
|
|
|
get_reserved_name('null', ''), headers={
|
|
|
|
'X-Backend-Allow-Reserved-Names': 'true',
|
|
|
|
'Accept': 'application/json'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 200, resp.body)
|
|
|
|
self.assertEqual(json.loads(resp.body),
|
|
|
|
self._expected_listing(containers))
|
|
|
|
|
|
|
|
req = Request.blank('/sda1/p/a?marker=%s' %
|
|
|
|
get_reserved_name('null', ''), headers={
|
|
|
|
'Accept': 'application/json'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 200, resp.body)
|
|
|
|
self.assertEqual(json.loads(resp.body),
|
|
|
|
[c for c in self._expected_listing(containers)
|
|
|
|
if get_reserved_name() not in c['name']])
|
|
|
|
|
|
|
|
req = Request.blank('/sda1/p/a?marker=%s' %
|
|
|
|
get_reserved_name('null', ''), headers={
|
|
|
|
'X-Backend-Allow-Reserved-Names': 'true',
|
|
|
|
'Accept': 'application/json'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 200, resp.body)
|
|
|
|
self.assertEqual(json.loads(resp.body),
|
|
|
|
self._expected_listing(containers))
|
|
|
|
|
|
|
|
req = Request.blank('/sda1/p/a?marker=%s' % quote(
|
|
|
|
self._expected_listing(containers)[0]['name']), headers={
|
|
|
|
'X-Backend-Allow-Reserved-Names': 'true',
|
|
|
|
'Accept': 'application/json'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 200, resp.body)
|
|
|
|
self.assertEqual(json.loads(resp.body),
|
|
|
|
self._expected_listing(containers)[1:])
|
|
|
|
|
|
|
|
def test_null_markers(self):
|
|
|
|
containers = [{
|
|
|
|
'name': get_reserved_name('null', ''),
|
|
|
|
'bytes': 200,
|
|
|
|
'count': 2,
|
|
|
|
'timestamp': next(self.ts),
|
|
|
|
}, {
|
|
|
|
'name': get_reserved_name('null', 'test01'),
|
|
|
|
'bytes': 200,
|
|
|
|
'count': 2,
|
|
|
|
'timestamp': next(self.ts),
|
|
|
|
}, {
|
|
|
|
'name': 'null',
|
|
|
|
'bytes': 300,
|
|
|
|
'count': 32,
|
|
|
|
'timestamp': next(self.ts),
|
|
|
|
}]
|
|
|
|
self._report_containers(containers)
|
|
|
|
|
|
|
|
req = Request.blank('/sda1/p/a?marker=%s' % get_reserved_name('null'),
|
|
|
|
headers={'Accept': 'application/json'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 200, resp.body)
|
|
|
|
self.assertEqual(json.loads(resp.body),
|
|
|
|
self._expected_listing(containers)[-1:])
|
|
|
|
|
|
|
|
req = Request.blank('/sda1/p/a?marker=%s' % get_reserved_name('null'),
|
|
|
|
headers={'X-Backend-Allow-Reserved-Names': 'true',
|
|
|
|
'Accept': 'application/json'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 200, resp.body)
|
|
|
|
self.assertEqual(json.loads(resp.body),
|
|
|
|
self._expected_listing(containers))
|
|
|
|
|
|
|
|
req = Request.blank('/sda1/p/a?marker=%s' %
|
|
|
|
get_reserved_name('null', ''), headers={
|
|
|
|
'X-Backend-Allow-Reserved-Names': 'true',
|
|
|
|
'Accept': 'application/json'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 200, resp.body)
|
|
|
|
self.assertEqual(json.loads(resp.body),
|
|
|
|
self._expected_listing(containers)[1:])
|
|
|
|
|
|
|
|
req = Request.blank('/sda1/p/a?marker=%s' %
|
|
|
|
get_reserved_name('null', 'test00'), headers={
|
|
|
|
'X-Backend-Allow-Reserved-Names': 'true',
|
|
|
|
'Accept': 'application/json'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 200, resp.body)
|
|
|
|
self.assertEqual(json.loads(resp.body),
|
|
|
|
self._expected_listing(containers)[1:])
|
|
|
|
|
2010-07-12 17:03:45 -05:00
|
|
|
def test_through_call(self):
|
2015-05-27 18:01:37 +02:00
|
|
|
inbuf = BytesIO()
|
2010-07-12 17:03:45 -05:00
|
|
|
errbuf = StringIO()
|
|
|
|
outbuf = StringIO()
|
2013-03-18 18:01:16 -07:00
|
|
|
|
2010-07-12 17:03:45 -05:00
|
|
|
def start_response(*args):
|
2018-10-23 00:57:50 -05:00
|
|
|
outbuf.write(args[0])
|
2013-03-18 18:01:16 -07:00
|
|
|
|
2010-07-12 17:03:45 -05:00
|
|
|
self.controller.__call__({'REQUEST_METHOD': 'GET',
|
|
|
|
'SCRIPT_NAME': '',
|
|
|
|
'PATH_INFO': '/sda1/p/a',
|
|
|
|
'SERVER_NAME': '127.0.0.1',
|
|
|
|
'SERVER_PORT': '8080',
|
|
|
|
'SERVER_PROTOCOL': 'HTTP/1.0',
|
|
|
|
'CONTENT_LENGTH': '0',
|
|
|
|
'wsgi.version': (1, 0),
|
|
|
|
'wsgi.url_scheme': 'http',
|
|
|
|
'wsgi.input': inbuf,
|
|
|
|
'wsgi.errors': errbuf,
|
|
|
|
'wsgi.multithread': False,
|
|
|
|
'wsgi.multiprocess': False,
|
|
|
|
'wsgi.run_once': False},
|
|
|
|
start_response)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(errbuf.getvalue(), '')
|
|
|
|
self.assertEqual(outbuf.getvalue()[:4], '404 ')
|
2010-07-12 17:03:45 -05:00
|
|
|
|
|
|
|
def test_through_call_invalid_path(self):
|
2015-05-27 18:01:37 +02:00
|
|
|
inbuf = BytesIO()
|
2010-07-12 17:03:45 -05:00
|
|
|
errbuf = StringIO()
|
|
|
|
outbuf = StringIO()
|
2013-03-18 18:01:16 -07:00
|
|
|
|
2010-07-12 17:03:45 -05:00
|
|
|
def start_response(*args):
|
2018-10-23 00:57:50 -05:00
|
|
|
outbuf.write(args[0])
|
2013-03-18 18:01:16 -07:00
|
|
|
|
2010-07-12 17:03:45 -05:00
|
|
|
self.controller.__call__({'REQUEST_METHOD': 'GET',
|
|
|
|
'SCRIPT_NAME': '',
|
|
|
|
'PATH_INFO': '/bob',
|
|
|
|
'SERVER_NAME': '127.0.0.1',
|
|
|
|
'SERVER_PORT': '8080',
|
|
|
|
'SERVER_PROTOCOL': 'HTTP/1.0',
|
|
|
|
'CONTENT_LENGTH': '0',
|
|
|
|
'wsgi.version': (1, 0),
|
|
|
|
'wsgi.url_scheme': 'http',
|
|
|
|
'wsgi.input': inbuf,
|
|
|
|
'wsgi.errors': errbuf,
|
|
|
|
'wsgi.multithread': False,
|
|
|
|
'wsgi.multiprocess': False,
|
|
|
|
'wsgi.run_once': False},
|
|
|
|
start_response)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(errbuf.getvalue(), '')
|
|
|
|
self.assertEqual(outbuf.getvalue()[:4], '400 ')
|
2010-07-12 17:03:45 -05:00
|
|
|
|
2013-03-18 18:01:16 -07:00
|
|
|
def test_through_call_invalid_path_utf8(self):
|
2015-05-27 18:01:37 +02:00
|
|
|
inbuf = BytesIO()
|
2013-03-18 18:01:16 -07:00
|
|
|
errbuf = StringIO()
|
|
|
|
outbuf = StringIO()
|
|
|
|
|
|
|
|
def start_response(*args):
|
2018-10-23 00:57:50 -05:00
|
|
|
outbuf.write(args[0])
|
2013-03-18 18:01:16 -07:00
|
|
|
|
|
|
|
self.controller.__call__({'REQUEST_METHOD': 'GET',
|
|
|
|
'SCRIPT_NAME': '',
|
2019-09-13 12:25:24 -05:00
|
|
|
'PATH_INFO': '/sda1/p/a/c\xd8\x3e%20',
|
2013-03-18 18:01:16 -07:00
|
|
|
'SERVER_NAME': '127.0.0.1',
|
|
|
|
'SERVER_PORT': '8080',
|
|
|
|
'SERVER_PROTOCOL': 'HTTP/1.0',
|
|
|
|
'CONTENT_LENGTH': '0',
|
|
|
|
'wsgi.version': (1, 0),
|
|
|
|
'wsgi.url_scheme': 'http',
|
|
|
|
'wsgi.input': inbuf,
|
|
|
|
'wsgi.errors': errbuf,
|
|
|
|
'wsgi.multithread': False,
|
|
|
|
'wsgi.multiprocess': False,
|
|
|
|
'wsgi.run_once': False},
|
|
|
|
start_response)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(errbuf.getvalue(), '')
|
|
|
|
self.assertEqual(outbuf.getvalue()[:4], '412 ')
|
2013-03-18 18:01:16 -07:00
|
|
|
|
2012-06-01 16:39:35 +02:00
|
|
|
def test_invalid_method_doesnt_exist(self):
|
|
|
|
errbuf = StringIO()
|
|
|
|
outbuf = StringIO()
|
2013-03-18 18:01:16 -07:00
|
|
|
|
2012-06-01 16:39:35 +02:00
|
|
|
def start_response(*args):
|
2018-10-23 00:57:50 -05:00
|
|
|
outbuf.write(args[0])
|
2013-03-18 18:01:16 -07:00
|
|
|
|
2012-06-01 16:39:35 +02:00
|
|
|
self.controller.__call__({'REQUEST_METHOD': 'method_doesnt_exist',
|
|
|
|
'PATH_INFO': '/sda1/p/a'},
|
|
|
|
start_response)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(errbuf.getvalue(), '')
|
|
|
|
self.assertEqual(outbuf.getvalue()[:4], '405 ')
|
2012-06-01 16:39:35 +02:00
|
|
|
|
|
|
|
def test_invalid_method_is_not_public(self):
|
|
|
|
errbuf = StringIO()
|
|
|
|
outbuf = StringIO()
|
2013-03-18 18:01:16 -07:00
|
|
|
|
2012-06-01 16:39:35 +02:00
|
|
|
def start_response(*args):
|
2018-10-23 00:57:50 -05:00
|
|
|
outbuf.write(args[0])
|
2013-03-18 18:01:16 -07:00
|
|
|
|
2012-06-01 16:39:35 +02:00
|
|
|
self.controller.__call__({'REQUEST_METHOD': '__init__',
|
|
|
|
'PATH_INFO': '/sda1/p/a'},
|
|
|
|
start_response)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(errbuf.getvalue(), '')
|
|
|
|
self.assertEqual(outbuf.getvalue()[:4], '405 ')
|
2012-06-01 16:39:35 +02:00
|
|
|
|
2012-06-06 03:39:53 +09:00
|
|
|
def test_params_format(self):
|
2013-08-16 16:24:00 -07:00
|
|
|
Request.blank('/sda1/p/a',
|
|
|
|
headers={'X-Timestamp': normalize_timestamp(1)},
|
|
|
|
environ={'REQUEST_METHOD': 'PUT'}).get_response(
|
|
|
|
self.controller)
|
2012-06-06 03:39:53 +09:00
|
|
|
for format in ('xml', 'json'):
|
|
|
|
req = Request.blank('/sda1/p/a?format=%s' % format,
|
|
|
|
environ={'REQUEST_METHOD': 'GET'})
|
2013-07-24 12:55:25 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 200)
|
2012-06-06 03:39:53 +09:00
|
|
|
|
2010-07-12 17:03:45 -05:00
|
|
|
def test_params_utf8(self):
|
2013-05-25 16:30:07 -04:00
|
|
|
# Bad UTF8 sequence, all parameters should cause 400 error
|
|
|
|
for param in ('delimiter', 'limit', 'marker', 'prefix', 'end_marker',
|
|
|
|
'format'):
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a?%s=\xce' % param,
|
|
|
|
environ={'REQUEST_METHOD': 'GET'})
|
2013-07-24 12:55:25 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 400,
|
|
|
|
"%d on param %s" % (resp.status_int, param))
|
2013-08-16 16:24:00 -07:00
|
|
|
Request.blank('/sda1/p/a',
|
|
|
|
headers={'X-Timestamp': normalize_timestamp(1)},
|
|
|
|
environ={'REQUEST_METHOD': 'PUT'}).get_response(
|
|
|
|
self.controller)
|
2013-05-25 16:30:07 -04:00
|
|
|
# Good UTF8 sequence, ignored for limit, doesn't affect other queries
|
2018-10-11 15:23:39 -07:00
|
|
|
for param in ('limit', 'marker', 'prefix', 'end_marker', 'format',
|
|
|
|
'delimiter'):
|
2010-07-12 17:03:45 -05:00
|
|
|
req = Request.blank('/sda1/p/a?%s=\xce\xa9' % param,
|
|
|
|
environ={'REQUEST_METHOD': 'GET'})
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 204,
|
|
|
|
"%d on param %s" % (resp.status_int, param))
|
2010-07-12 17:03:45 -05:00
|
|
|
|
2013-10-29 16:10:47 -06:00
|
|
|
def test_PUT_auto_create(self):
|
2011-10-26 21:42:24 +00:00
|
|
|
headers = {'x-put-timestamp': normalize_timestamp(1),
|
|
|
|
'x-delete-timestamp': normalize_timestamp(0),
|
|
|
|
'x-object-count': '0',
|
|
|
|
'x-bytes-used': '0'}
|
|
|
|
|
2013-08-16 16:24:00 -07:00
|
|
|
req = Request.blank('/sda1/p/a/c',
|
|
|
|
environ={'REQUEST_METHOD': 'PUT'},
|
|
|
|
headers=dict(headers))
|
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 404)
|
2011-10-26 21:42:24 +00:00
|
|
|
|
2013-08-16 16:24:00 -07:00
|
|
|
req = Request.blank('/sda1/p/.a/c',
|
|
|
|
environ={'REQUEST_METHOD': 'PUT'},
|
|
|
|
headers=dict(headers))
|
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 201)
|
2011-10-26 21:42:24 +00:00
|
|
|
|
2013-08-16 16:24:00 -07:00
|
|
|
req = Request.blank('/sda1/p/a/.c',
|
|
|
|
environ={'REQUEST_METHOD': 'PUT'},
|
|
|
|
headers=dict(headers))
|
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.status_int, 404)
|
2011-10-26 21:42:24 +00:00
|
|
|
|
2012-11-02 12:02:02 -07:00
|
|
|
def test_content_type_on_HEAD(self):
|
2013-08-16 16:24:00 -07:00
|
|
|
Request.blank('/sda1/p/a',
|
|
|
|
headers={'X-Timestamp': normalize_timestamp(1)},
|
|
|
|
environ={'REQUEST_METHOD': 'PUT'}).get_response(
|
|
|
|
self.controller)
|
2012-11-02 12:02:02 -07:00
|
|
|
|
|
|
|
env = {'REQUEST_METHOD': 'HEAD'}
|
|
|
|
|
|
|
|
req = Request.blank('/sda1/p/a?format=xml', environ=env)
|
Refactor how we pick listings' content type.
There were a few different places where we had some repeated code to
figure out what format an account or container listing response should
be in (text, JSON, or XML). Now that's been pulled into a single
function.
As part of this, you can now raise HTTPException subclasses in proxy
controllers instead of laboriously plumbing error responses all the
way back up to swift.proxy.server.Application.handle_request(). This
lets us avoid certain ugly patterns, like the one where a method
returns a tuple of (x, y, z, error) and the caller has to see if it
got (value, value, value, None) or (None, None, None, errorvalue). Now
we can just raise the error.
Change-Id: I316873df289160d526487ad116f6fbb9a575e3de
2013-08-14 11:55:15 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.content_type, 'application/xml')
|
2012-11-02 12:02:02 -07:00
|
|
|
|
|
|
|
req = Request.blank('/sda1/p/a?format=json', environ=env)
|
Refactor how we pick listings' content type.
There were a few different places where we had some repeated code to
figure out what format an account or container listing response should
be in (text, JSON, or XML). Now that's been pulled into a single
function.
As part of this, you can now raise HTTPException subclasses in proxy
controllers instead of laboriously plumbing error responses all the
way back up to swift.proxy.server.Application.handle_request(). This
lets us avoid certain ugly patterns, like the one where a method
returns a tuple of (x, y, z, error) and the caller has to see if it
got (value, value, value, None) or (None, None, None, errorvalue). Now
we can just raise the error.
Change-Id: I316873df289160d526487ad116f6fbb9a575e3de
2013-08-14 11:55:15 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.content_type, 'application/json')
|
|
|
|
self.assertEqual(resp.charset, 'utf-8')
|
2012-11-02 12:02:02 -07:00
|
|
|
|
|
|
|
req = Request.blank('/sda1/p/a', environ=env)
|
Refactor how we pick listings' content type.
There were a few different places where we had some repeated code to
figure out what format an account or container listing response should
be in (text, JSON, or XML). Now that's been pulled into a single
function.
As part of this, you can now raise HTTPException subclasses in proxy
controllers instead of laboriously plumbing error responses all the
way back up to swift.proxy.server.Application.handle_request(). This
lets us avoid certain ugly patterns, like the one where a method
returns a tuple of (x, y, z, error) and the caller has to see if it
got (value, value, value, None) or (None, None, None, errorvalue). Now
we can just raise the error.
Change-Id: I316873df289160d526487ad116f6fbb9a575e3de
2013-08-14 11:55:15 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.content_type, 'text/plain')
|
|
|
|
self.assertEqual(resp.charset, 'utf-8')
|
2012-11-02 12:02:02 -07:00
|
|
|
|
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a', headers={'Accept': 'application/json'}, environ=env)
|
Refactor how we pick listings' content type.
There were a few different places where we had some repeated code to
figure out what format an account or container listing response should
be in (text, JSON, or XML). Now that's been pulled into a single
function.
As part of this, you can now raise HTTPException subclasses in proxy
controllers instead of laboriously plumbing error responses all the
way back up to swift.proxy.server.Application.handle_request(). This
lets us avoid certain ugly patterns, like the one where a method
returns a tuple of (x, y, z, error) and the caller has to see if it
got (value, value, value, None) or (None, None, None, errorvalue). Now
we can just raise the error.
Change-Id: I316873df289160d526487ad116f6fbb9a575e3de
2013-08-14 11:55:15 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.content_type, 'application/json')
|
|
|
|
self.assertEqual(resp.charset, 'utf-8')
|
2012-11-02 12:02:02 -07:00
|
|
|
|
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a', headers={'Accept': 'application/xml'}, environ=env)
|
2013-08-16 16:24:00 -07:00
|
|
|
resp = req.get_response(self.controller)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(resp.content_type, 'application/xml')
|
|
|
|
self.assertEqual(resp.charset, 'utf-8')
|
2012-11-02 12:02:02 -07:00
|
|
|
|
2012-12-17 06:39:25 -05:00
|
|
|
def test_serv_reserv(self):
|
2013-08-31 22:36:58 -04:00
|
|
|
# Test replication_server flag was set from configuration file.
|
2012-12-17 06:39:25 -05:00
|
|
|
conf = {'devices': self.testdir, 'mount_check': 'false'}
|
2017-06-07 09:07:59 +08:00
|
|
|
self.assertIsNone(AccountController(conf).replication_server)
|
2012-12-17 06:39:25 -05:00
|
|
|
for val in [True, '1', 'True', 'true']:
|
|
|
|
conf['replication_server'] = val
|
|
|
|
self.assertTrue(AccountController(conf).replication_server)
|
|
|
|
for val in [False, 0, '0', 'False', 'false', 'test_string']:
|
|
|
|
conf['replication_server'] = val
|
|
|
|
self.assertFalse(AccountController(conf).replication_server)
|
|
|
|
|
|
|
|
def test_list_allowed_methods(self):
|
2013-08-31 22:36:58 -04:00
|
|
|
# Test list of allowed_methods
|
2013-05-23 20:16:21 +04:00
|
|
|
obj_methods = ['DELETE', 'PUT', 'HEAD', 'GET', 'POST']
|
|
|
|
repl_methods = ['REPLICATE']
|
|
|
|
for method_name in obj_methods:
|
|
|
|
method = getattr(self.controller, method_name)
|
|
|
|
self.assertFalse(hasattr(method, 'replication'))
|
|
|
|
for method_name in repl_methods:
|
|
|
|
method = getattr(self.controller, method_name)
|
2013-10-02 21:27:40 +02:00
|
|
|
self.assertEqual(method.replication, True)
|
2012-12-17 06:39:25 -05:00
|
|
|
|
|
|
|
def test_correct_allowed_method(self):
|
2013-08-31 22:36:58 -04:00
|
|
|
# Test correct work for allowed method using
|
|
|
|
# swift.account.server.AccountController.__call__
|
2015-05-27 18:01:37 +02:00
|
|
|
inbuf = BytesIO()
|
2012-12-17 06:39:25 -05:00
|
|
|
errbuf = StringIO()
|
2013-05-23 20:16:21 +04:00
|
|
|
self.controller = AccountController(
|
2013-09-01 01:54:03 -04:00
|
|
|
{'devices': self.testdir,
|
|
|
|
'mount_check': 'false',
|
|
|
|
'replication_server': 'false'})
|
2012-12-17 06:39:25 -05:00
|
|
|
|
|
|
|
def start_response(*args):
|
2018-12-27 23:01:52 +00:00
|
|
|
pass
|
2012-12-17 06:39:25 -05:00
|
|
|
|
2013-05-23 20:16:21 +04:00
|
|
|
method = 'PUT'
|
2012-12-17 06:39:25 -05:00
|
|
|
env = {'REQUEST_METHOD': method,
|
|
|
|
'SCRIPT_NAME': '',
|
|
|
|
'PATH_INFO': '/sda1/p/a/c',
|
|
|
|
'SERVER_NAME': '127.0.0.1',
|
|
|
|
'SERVER_PORT': '8080',
|
|
|
|
'SERVER_PROTOCOL': 'HTTP/1.0',
|
|
|
|
'CONTENT_LENGTH': '0',
|
|
|
|
'wsgi.version': (1, 0),
|
|
|
|
'wsgi.url_scheme': 'http',
|
|
|
|
'wsgi.input': inbuf,
|
|
|
|
'wsgi.errors': errbuf,
|
|
|
|
'wsgi.multithread': False,
|
|
|
|
'wsgi.multiprocess': False,
|
|
|
|
'wsgi.run_once': False}
|
|
|
|
|
2013-05-23 20:16:21 +04:00
|
|
|
method_res = mock.MagicMock()
|
|
|
|
mock_method = public(lambda x: mock.MagicMock(return_value=method_res))
|
2012-12-17 06:39:25 -05:00
|
|
|
with mock.patch.object(self.controller, method,
|
2013-05-23 20:16:21 +04:00
|
|
|
new=mock_method):
|
|
|
|
mock_method.replication = False
|
2014-12-08 23:28:48 +05:30
|
|
|
response = self.controller(env, start_response)
|
2013-05-23 20:16:21 +04:00
|
|
|
self.assertEqual(response, method_res)
|
2012-12-17 06:39:25 -05:00
|
|
|
|
|
|
|
def test_not_allowed_method(self):
|
2013-08-31 22:36:58 -04:00
|
|
|
# Test correct work for NOT allowed method using
|
|
|
|
# swift.account.server.AccountController.__call__
|
2015-05-27 18:01:37 +02:00
|
|
|
inbuf = BytesIO()
|
2012-12-17 06:39:25 -05:00
|
|
|
errbuf = StringIO()
|
2013-05-23 20:16:21 +04:00
|
|
|
self.controller = AccountController(
|
|
|
|
{'devices': self.testdir, 'mount_check': 'false',
|
|
|
|
'replication_server': 'false'})
|
2012-12-17 06:39:25 -05:00
|
|
|
|
|
|
|
def start_response(*args):
|
2018-12-27 23:01:52 +00:00
|
|
|
pass
|
2012-12-17 06:39:25 -05:00
|
|
|
|
2013-05-23 20:16:21 +04:00
|
|
|
method = 'PUT'
|
2012-12-17 06:39:25 -05:00
|
|
|
env = {'REQUEST_METHOD': method,
|
|
|
|
'SCRIPT_NAME': '',
|
|
|
|
'PATH_INFO': '/sda1/p/a/c',
|
|
|
|
'SERVER_NAME': '127.0.0.1',
|
|
|
|
'SERVER_PORT': '8080',
|
|
|
|
'SERVER_PROTOCOL': 'HTTP/1.0',
|
|
|
|
'CONTENT_LENGTH': '0',
|
|
|
|
'wsgi.version': (1, 0),
|
|
|
|
'wsgi.url_scheme': 'http',
|
|
|
|
'wsgi.input': inbuf,
|
|
|
|
'wsgi.errors': errbuf,
|
|
|
|
'wsgi.multithread': False,
|
|
|
|
'wsgi.multiprocess': False,
|
|
|
|
'wsgi.run_once': False}
|
|
|
|
|
2018-10-23 00:57:50 -05:00
|
|
|
answer = [b'<html><h1>Method Not Allowed</h1><p>The method is not '
|
|
|
|
b'allowed for this resource.</p></html>']
|
2013-05-23 20:16:21 +04:00
|
|
|
mock_method = replication(public(lambda x: mock.MagicMock()))
|
2012-12-17 06:39:25 -05:00
|
|
|
with mock.patch.object(self.controller, method,
|
2013-05-23 20:16:21 +04:00
|
|
|
new=mock_method):
|
|
|
|
mock_method.replication = True
|
2012-12-17 06:39:25 -05:00
|
|
|
response = self.controller.__call__(env, start_response)
|
|
|
|
self.assertEqual(response, answer)
|
2010-07-12 17:03:45 -05:00
|
|
|
|
2014-12-08 23:28:48 +05:30
|
|
|
def test_call_incorrect_replication_method(self):
|
2015-05-27 18:01:37 +02:00
|
|
|
inbuf = BytesIO()
|
2014-12-08 23:28:48 +05:30
|
|
|
errbuf = StringIO()
|
|
|
|
outbuf = StringIO()
|
|
|
|
self.controller = AccountController(
|
|
|
|
{'devices': self.testdir, 'mount_check': 'false',
|
|
|
|
'replication_server': 'true'})
|
|
|
|
|
|
|
|
def start_response(*args):
|
2018-10-23 00:57:50 -05:00
|
|
|
outbuf.write(args[0])
|
2014-12-08 23:28:48 +05:30
|
|
|
|
|
|
|
obj_methods = ['DELETE', 'PUT', 'HEAD', 'GET', 'POST', 'OPTIONS']
|
|
|
|
for method in obj_methods:
|
|
|
|
env = {'REQUEST_METHOD': method,
|
|
|
|
'SCRIPT_NAME': '',
|
|
|
|
'PATH_INFO': '/sda1/p/a/c',
|
|
|
|
'SERVER_NAME': '127.0.0.1',
|
|
|
|
'SERVER_PORT': '8080',
|
|
|
|
'SERVER_PROTOCOL': 'HTTP/1.0',
|
|
|
|
'CONTENT_LENGTH': '0',
|
|
|
|
'wsgi.version': (1, 0),
|
|
|
|
'wsgi.url_scheme': 'http',
|
|
|
|
'wsgi.input': inbuf,
|
|
|
|
'wsgi.errors': errbuf,
|
|
|
|
'wsgi.multithread': False,
|
|
|
|
'wsgi.multiprocess': False,
|
|
|
|
'wsgi.run_once': False}
|
|
|
|
self.controller(env, start_response)
|
2015-08-05 22:25:46 +05:30
|
|
|
self.assertEqual(errbuf.getvalue(), '')
|
|
|
|
self.assertEqual(outbuf.getvalue()[:4], '405 ')
|
2014-12-08 23:28:48 +05:30
|
|
|
|
2015-11-06 01:49:58 +00:00
|
|
|
def test__call__raise_timeout(self):
|
|
|
|
inbuf = WsgiBytesIO()
|
|
|
|
errbuf = StringIO()
|
|
|
|
self.logger = debug_logger('test')
|
|
|
|
self.account_controller = AccountController(
|
|
|
|
{'devices': self.testdir, 'mount_check': 'false',
|
|
|
|
'replication_server': 'false', 'log_requests': 'false'},
|
|
|
|
logger=self.logger)
|
|
|
|
|
|
|
|
def start_response(*args):
|
2018-12-27 23:01:52 +00:00
|
|
|
pass
|
2015-11-06 01:49:58 +00:00
|
|
|
|
|
|
|
method = 'PUT'
|
|
|
|
|
|
|
|
env = {'REQUEST_METHOD': method,
|
|
|
|
'SCRIPT_NAME': '',
|
|
|
|
'PATH_INFO': '/sda1/p/a/c',
|
|
|
|
'SERVER_NAME': '127.0.0.1',
|
|
|
|
'SERVER_PORT': '8080',
|
|
|
|
'SERVER_PROTOCOL': 'HTTP/1.0',
|
|
|
|
'CONTENT_LENGTH': '0',
|
|
|
|
'wsgi.version': (1, 0),
|
|
|
|
'wsgi.url_scheme': 'http',
|
|
|
|
'wsgi.input': inbuf,
|
|
|
|
'wsgi.errors': errbuf,
|
|
|
|
'wsgi.multithread': False,
|
|
|
|
'wsgi.multiprocess': False,
|
|
|
|
'wsgi.run_once': False}
|
|
|
|
|
|
|
|
@public
|
|
|
|
def mock_put_method(*args, **kwargs):
|
|
|
|
raise Exception()
|
|
|
|
|
|
|
|
with mock.patch.object(self.account_controller, method,
|
|
|
|
new=mock_put_method):
|
|
|
|
response = self.account_controller.__call__(env, start_response)
|
2018-10-23 00:57:50 -05:00
|
|
|
self.assertTrue(response[0].decode('ascii').startswith(
|
2015-11-06 01:49:58 +00:00
|
|
|
'Traceback (most recent call last):'))
|
|
|
|
self.assertEqual(self.logger.get_lines_for_level('error'), [
|
|
|
|
'ERROR __call__ error with %(method)s %(path)s : ' % {
|
|
|
|
'method': 'PUT', 'path': '/sda1/p/a/c'},
|
|
|
|
])
|
|
|
|
self.assertEqual(self.logger.get_lines_for_level('info'), [])
|
|
|
|
|
2014-02-17 10:31:20 +00:00
|
|
|
def test_GET_log_requests_true(self):
|
|
|
|
self.controller.logger = FakeLogger()
|
|
|
|
self.controller.log_requests = True
|
|
|
|
|
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'GET'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 404)
|
|
|
|
self.assertTrue(self.controller.logger.log_dict['info'])
|
|
|
|
|
|
|
|
def test_GET_log_requests_false(self):
|
|
|
|
self.controller.logger = FakeLogger()
|
|
|
|
self.controller.log_requests = False
|
|
|
|
req = Request.blank('/sda1/p/a', environ={'REQUEST_METHOD': 'GET'})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 404)
|
|
|
|
self.assertFalse(self.controller.logger.log_dict['info'])
|
|
|
|
|
2014-03-26 22:55:55 +00:00
|
|
|
def test_log_line_format(self):
|
|
|
|
req = Request.blank(
|
|
|
|
'/sda1/p/a',
|
|
|
|
environ={'REQUEST_METHOD': 'HEAD', 'REMOTE_ADDR': '1.2.3.4'})
|
|
|
|
self.controller.logger = FakeLogger()
|
|
|
|
with mock.patch(
|
2018-03-01 11:31:12 +01:00
|
|
|
'time.time',
|
|
|
|
mock.MagicMock(side_effect=[10000.0, 10001.0, 10002.0,
|
|
|
|
10002.0])):
|
2014-03-26 22:55:55 +00:00
|
|
|
with mock.patch(
|
2018-03-01 11:31:12 +01:00
|
|
|
'os.getpid', mock.MagicMock(return_value=1234)):
|
|
|
|
req.get_response(self.controller)
|
2014-03-26 22:55:55 +00:00
|
|
|
self.assertEqual(
|
|
|
|
self.controller.logger.log_dict['info'],
|
2018-03-01 11:31:12 +01:00
|
|
|
[(('1.2.3.4 - - [01/Jan/1970:02:46:42 +0000] "HEAD /sda1/p/a" 404 '
|
2014-11-27 18:42:49 +09:00
|
|
|
'- "-" "-" "-" 2.0000 "-" 1234 -',), {})])
|
2014-03-26 22:55:55 +00:00
|
|
|
|
2014-05-27 19:02:52 -07:00
|
|
|
def test_policy_stats_with_legacy(self):
|
|
|
|
ts = itertools.count()
|
|
|
|
# create the account
|
|
|
|
req = Request.blank('/sda1/p/a', method='PUT', headers={
|
2015-06-15 22:10:45 +05:30
|
|
|
'X-Timestamp': normalize_timestamp(next(ts))})
|
2014-05-27 19:02:52 -07:00
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 201) # sanity
|
|
|
|
|
|
|
|
# add a container
|
|
|
|
req = Request.blank('/sda1/p/a/c1', method='PUT', headers={
|
2015-06-15 22:10:45 +05:30
|
|
|
'X-Put-Timestamp': normalize_timestamp(next(ts)),
|
2014-05-27 19:02:52 -07:00
|
|
|
'X-Delete-Timestamp': '0',
|
|
|
|
'X-Object-Count': '2',
|
|
|
|
'X-Bytes-Used': '4',
|
|
|
|
})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 201)
|
|
|
|
|
|
|
|
# read back rollup
|
|
|
|
for method in ('GET', 'HEAD'):
|
|
|
|
req = Request.blank('/sda1/p/a', method=method)
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int // 100, 2)
|
2015-08-05 22:25:46 +05:30
|
|
|
self.assertEqual(resp.headers['X-Account-Object-Count'], '2')
|
|
|
|
self.assertEqual(resp.headers['X-Account-Bytes-Used'], '4')
|
|
|
|
self.assertEqual(
|
2014-05-27 19:02:52 -07:00
|
|
|
resp.headers['X-Account-Storage-Policy-%s-Object-Count' %
|
|
|
|
POLICIES[0].name], '2')
|
2015-08-05 22:25:46 +05:30
|
|
|
self.assertEqual(
|
2014-05-27 19:02:52 -07:00
|
|
|
resp.headers['X-Account-Storage-Policy-%s-Bytes-Used' %
|
|
|
|
POLICIES[0].name], '4')
|
2015-08-05 22:25:46 +05:30
|
|
|
self.assertEqual(
|
2014-09-11 06:55:45 -07:00
|
|
|
resp.headers['X-Account-Storage-Policy-%s-Container-Count' %
|
|
|
|
POLICIES[0].name], '1')
|
2014-05-27 19:02:52 -07:00
|
|
|
|
|
|
|
def test_policy_stats_non_default(self):
|
|
|
|
ts = itertools.count()
|
|
|
|
# create the account
|
|
|
|
req = Request.blank('/sda1/p/a', method='PUT', headers={
|
2015-06-15 22:10:45 +05:30
|
|
|
'X-Timestamp': normalize_timestamp(next(ts))})
|
2014-05-27 19:02:52 -07:00
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 201) # sanity
|
|
|
|
|
|
|
|
# add a container
|
|
|
|
non_default_policies = [p for p in POLICIES if not p.is_default]
|
|
|
|
policy = random.choice(non_default_policies)
|
|
|
|
req = Request.blank('/sda1/p/a/c1', method='PUT', headers={
|
2015-06-15 22:10:45 +05:30
|
|
|
'X-Put-Timestamp': normalize_timestamp(next(ts)),
|
2014-05-27 19:02:52 -07:00
|
|
|
'X-Delete-Timestamp': '0',
|
|
|
|
'X-Object-Count': '2',
|
|
|
|
'X-Bytes-Used': '4',
|
2014-06-23 12:52:50 -07:00
|
|
|
'X-Backend-Storage-Policy-Index': policy.idx,
|
2014-05-27 19:02:52 -07:00
|
|
|
})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 201)
|
|
|
|
|
|
|
|
# read back rollup
|
|
|
|
for method in ('GET', 'HEAD'):
|
|
|
|
req = Request.blank('/sda1/p/a', method=method)
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int // 100, 2)
|
2015-08-05 22:25:46 +05:30
|
|
|
self.assertEqual(resp.headers['X-Account-Object-Count'], '2')
|
|
|
|
self.assertEqual(resp.headers['X-Account-Bytes-Used'], '4')
|
|
|
|
self.assertEqual(
|
2014-05-27 19:02:52 -07:00
|
|
|
resp.headers['X-Account-Storage-Policy-%s-Object-Count' %
|
|
|
|
policy.name], '2')
|
2015-08-05 22:25:46 +05:30
|
|
|
self.assertEqual(
|
2014-05-27 19:02:52 -07:00
|
|
|
resp.headers['X-Account-Storage-Policy-%s-Bytes-Used' %
|
|
|
|
policy.name], '4')
|
2015-08-05 22:25:46 +05:30
|
|
|
self.assertEqual(
|
2014-09-11 06:55:45 -07:00
|
|
|
resp.headers['X-Account-Storage-Policy-%s-Container-Count' %
|
|
|
|
policy.name], '1')
|
2014-05-27 19:02:52 -07:00
|
|
|
|
|
|
|
def test_empty_policy_stats(self):
|
|
|
|
ts = itertools.count()
|
|
|
|
# create the account
|
|
|
|
req = Request.blank('/sda1/p/a', method='PUT', headers={
|
2015-06-15 22:10:45 +05:30
|
|
|
'X-Timestamp': normalize_timestamp(next(ts))})
|
2014-05-27 19:02:52 -07:00
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 201) # sanity
|
|
|
|
|
|
|
|
for method in ('GET', 'HEAD'):
|
|
|
|
req = Request.blank('/sda1/p/a', method=method)
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int // 100, 2)
|
|
|
|
for key in resp.headers:
|
2016-12-12 15:18:52 +07:00
|
|
|
self.assertNotIn('storage-policy', key.lower())
|
2014-05-27 19:02:52 -07:00
|
|
|
|
|
|
|
def test_empty_except_for_used_policies(self):
|
|
|
|
ts = itertools.count()
|
|
|
|
# create the account
|
|
|
|
req = Request.blank('/sda1/p/a', method='PUT', headers={
|
2015-06-15 22:10:45 +05:30
|
|
|
'X-Timestamp': normalize_timestamp(next(ts))})
|
2014-05-27 19:02:52 -07:00
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 201) # sanity
|
|
|
|
|
|
|
|
# starts empty
|
|
|
|
for method in ('GET', 'HEAD'):
|
|
|
|
req = Request.blank('/sda1/p/a', method=method)
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int // 100, 2)
|
|
|
|
for key in resp.headers:
|
2016-12-12 15:18:52 +07:00
|
|
|
self.assertNotIn('storage-policy', key.lower())
|
2014-05-27 19:02:52 -07:00
|
|
|
|
|
|
|
# add a container
|
|
|
|
policy = random.choice(POLICIES)
|
|
|
|
req = Request.blank('/sda1/p/a/c1', method='PUT', headers={
|
2015-06-15 22:10:45 +05:30
|
|
|
'X-Put-Timestamp': normalize_timestamp(next(ts)),
|
2014-05-27 19:02:52 -07:00
|
|
|
'X-Delete-Timestamp': '0',
|
|
|
|
'X-Object-Count': '2',
|
|
|
|
'X-Bytes-Used': '4',
|
2014-06-23 12:52:50 -07:00
|
|
|
'X-Backend-Storage-Policy-Index': policy.idx,
|
2014-05-27 19:02:52 -07:00
|
|
|
})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 201)
|
|
|
|
|
|
|
|
# only policy of the created container should be in headers
|
|
|
|
for method in ('GET', 'HEAD'):
|
|
|
|
req = Request.blank('/sda1/p/a', method=method)
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int // 100, 2)
|
|
|
|
for key in resp.headers:
|
|
|
|
if 'storage-policy' in key.lower():
|
2017-06-22 13:57:11 +02:00
|
|
|
self.assertIn(policy.name.lower(), key.lower())
|
2014-05-27 19:02:52 -07:00
|
|
|
|
|
|
|
def test_multiple_policies_in_use(self):
|
|
|
|
ts = itertools.count()
|
|
|
|
# create the account
|
|
|
|
req = Request.blank('/sda1/p/a', method='PUT', headers={
|
2015-06-15 22:10:45 +05:30
|
|
|
'X-Timestamp': normalize_timestamp(next(ts))})
|
2014-05-27 19:02:52 -07:00
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 201) # sanity
|
|
|
|
|
|
|
|
# add some containers
|
|
|
|
for policy in POLICIES:
|
|
|
|
count = policy.idx * 100 # good as any integer
|
|
|
|
container_path = '/sda1/p/a/c_%s' % policy.name
|
|
|
|
req = Request.blank(
|
|
|
|
container_path, method='PUT', headers={
|
2015-06-15 22:10:45 +05:30
|
|
|
'X-Put-Timestamp': normalize_timestamp(next(ts)),
|
2014-05-27 19:02:52 -07:00
|
|
|
'X-Delete-Timestamp': '0',
|
|
|
|
'X-Object-Count': count,
|
|
|
|
'X-Bytes-Used': count,
|
2014-06-23 12:52:50 -07:00
|
|
|
'X-Backend-Storage-Policy-Index': policy.idx,
|
2014-05-27 19:02:52 -07:00
|
|
|
})
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int, 201)
|
|
|
|
|
|
|
|
req = Request.blank('/sda1/p/a', method='HEAD')
|
|
|
|
resp = req.get_response(self.controller)
|
|
|
|
self.assertEqual(resp.status_int // 100, 2)
|
|
|
|
|
|
|
|
# check container counts in roll up headers
|
|
|
|
total_object_count = 0
|
|
|
|
total_bytes_used = 0
|
|
|
|
for key in resp.headers:
|
|
|
|
if 'storage-policy' not in key.lower():
|
|
|
|
continue
|
|
|
|
for policy in POLICIES:
|
|
|
|
if policy.name.lower() not in key.lower():
|
|
|
|
continue
|
|
|
|
if key.lower().endswith('object-count'):
|
|
|
|
object_count = int(resp.headers[key])
|
|
|
|
self.assertEqual(policy.idx * 100, object_count)
|
|
|
|
total_object_count += object_count
|
|
|
|
if key.lower().endswith('bytes-used'):
|
|
|
|
bytes_used = int(resp.headers[key])
|
|
|
|
self.assertEqual(policy.idx * 100, bytes_used)
|
|
|
|
total_bytes_used += bytes_used
|
|
|
|
|
|
|
|
expected_total_count = sum([p.idx * 100 for p in POLICIES])
|
|
|
|
self.assertEqual(expected_total_count, total_object_count)
|
|
|
|
self.assertEqual(expected_total_count, total_bytes_used)
|
|
|
|
|
|
|
|
|
|
|
|
@patch_policies([StoragePolicy(0, 'zero', False),
|
|
|
|
StoragePolicy(1, 'one', True),
|
|
|
|
StoragePolicy(2, 'two', False),
|
|
|
|
StoragePolicy(3, 'three', False)])
|
|
|
|
class TestNonLegacyDefaultStoragePolicy(TestAccountController):
|
|
|
|
pass
|
2014-02-17 10:31:20 +00:00
|
|
|
|
2017-09-11 22:08:12 +00:00
|
|
|
|
2010-07-12 17:03:45 -05:00
|
|
|
if __name__ == '__main__':
|
|
|
|
unittest.main()
|