2014-06-10 22:17:47 -07: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 itertools
|
|
|
|
import time
|
|
|
|
import unittest
|
2019-09-13 12:25:24 -05:00
|
|
|
import json
|
2014-06-10 22:17:47 -07:00
|
|
|
|
|
|
|
import mock
|
|
|
|
|
|
|
|
from swift.account import utils, backend
|
2019-09-13 12:25:24 -05:00
|
|
|
from swift.common.storage_policy import POLICIES, StoragePolicy
|
|
|
|
from swift.common.swob import Request
|
2014-06-10 22:17:47 -07:00
|
|
|
from swift.common.utils import Timestamp
|
2016-03-02 10:28:51 +00:00
|
|
|
from swift.common.header_key_dict import HeaderKeyDict
|
2019-09-13 12:25:24 -05:00
|
|
|
from swift.common.request_helpers import get_reserved_name
|
2014-06-10 22:17:47 -07:00
|
|
|
|
2019-09-13 12:25:24 -05:00
|
|
|
from test.unit import patch_policies, make_timestamp_iter
|
2022-07-07 17:27:49 +10:00
|
|
|
from test.unit.common.test_db import TestDbBase
|
2014-06-10 22:17:47 -07:00
|
|
|
|
|
|
|
|
|
|
|
class TestFakeAccountBroker(unittest.TestCase):
|
|
|
|
|
|
|
|
def test_fake_broker_get_info(self):
|
|
|
|
broker = utils.FakeAccountBroker()
|
|
|
|
now = time.time()
|
|
|
|
with mock.patch('time.time', new=lambda: now):
|
|
|
|
info = broker.get_info()
|
|
|
|
timestamp = Timestamp(now)
|
|
|
|
expected = {
|
|
|
|
'container_count': 0,
|
|
|
|
'object_count': 0,
|
|
|
|
'bytes_used': 0,
|
|
|
|
'created_at': timestamp.internal,
|
|
|
|
'put_timestamp': timestamp.internal,
|
|
|
|
}
|
|
|
|
self.assertEqual(info, expected)
|
|
|
|
|
|
|
|
def test_fake_broker_list_containers_iter(self):
|
|
|
|
broker = utils.FakeAccountBroker()
|
|
|
|
self.assertEqual(broker.list_containers_iter(), [])
|
|
|
|
|
|
|
|
def test_fake_broker_metadata(self):
|
|
|
|
broker = utils.FakeAccountBroker()
|
|
|
|
self.assertEqual(broker.metadata, {})
|
|
|
|
|
|
|
|
def test_fake_broker_get_policy_stats(self):
|
|
|
|
broker = utils.FakeAccountBroker()
|
|
|
|
self.assertEqual(broker.get_policy_stats(), {})
|
|
|
|
|
|
|
|
|
2022-07-07 17:27:49 +10:00
|
|
|
class TestAccountUtils(TestDbBase):
|
|
|
|
server_type = 'account'
|
2014-06-10 22:17:47 -07:00
|
|
|
|
2019-09-13 12:25:24 -05:00
|
|
|
def setUp(self):
|
2022-07-07 17:27:49 +10:00
|
|
|
super(TestAccountUtils, self).setUp()
|
2019-09-13 12:25:24 -05:00
|
|
|
self.ts = make_timestamp_iter()
|
|
|
|
|
2014-06-10 22:17:47 -07:00
|
|
|
def test_get_response_headers_fake_broker(self):
|
|
|
|
broker = utils.FakeAccountBroker()
|
|
|
|
now = time.time()
|
|
|
|
expected = {
|
|
|
|
'X-Account-Container-Count': 0,
|
|
|
|
'X-Account-Object-Count': 0,
|
|
|
|
'X-Account-Bytes-Used': 0,
|
|
|
|
'X-Timestamp': Timestamp(now).normal,
|
|
|
|
'X-PUT-Timestamp': Timestamp(now).normal,
|
|
|
|
}
|
|
|
|
with mock.patch('time.time', new=lambda: now):
|
|
|
|
resp_headers = utils.get_response_headers(broker)
|
|
|
|
self.assertEqual(resp_headers, expected)
|
|
|
|
|
|
|
|
def test_get_response_headers_empty_memory_broker(self):
|
2022-07-07 17:27:49 +10:00
|
|
|
broker = backend.AccountBroker(self.db_path, account='a')
|
2014-06-10 22:17:47 -07:00
|
|
|
now = time.time()
|
|
|
|
with mock.patch('time.time', new=lambda: now):
|
|
|
|
broker.initialize(Timestamp(now).internal)
|
|
|
|
expected = {
|
|
|
|
'X-Account-Container-Count': 0,
|
|
|
|
'X-Account-Object-Count': 0,
|
|
|
|
'X-Account-Bytes-Used': 0,
|
|
|
|
'X-Timestamp': Timestamp(now).normal,
|
|
|
|
'X-PUT-Timestamp': Timestamp(now).normal,
|
|
|
|
}
|
|
|
|
resp_headers = utils.get_response_headers(broker)
|
|
|
|
self.assertEqual(resp_headers, expected)
|
|
|
|
|
|
|
|
@patch_policies
|
|
|
|
def test_get_response_headers_with_data(self):
|
2022-07-07 17:27:49 +10:00
|
|
|
broker = backend.AccountBroker(self.db_path, account='a')
|
2014-06-10 22:17:47 -07:00
|
|
|
now = time.time()
|
|
|
|
with mock.patch('time.time', new=lambda: now):
|
|
|
|
broker.initialize(Timestamp(now).internal)
|
|
|
|
# add some container data
|
|
|
|
ts = (Timestamp(t).internal for t in itertools.count(int(now)))
|
|
|
|
total_containers = 0
|
|
|
|
total_objects = 0
|
|
|
|
total_bytes = 0
|
|
|
|
for policy in POLICIES:
|
2015-06-15 22:10:45 +05:30
|
|
|
delete_timestamp = next(ts)
|
|
|
|
put_timestamp = next(ts)
|
2014-06-10 22:17:47 -07:00
|
|
|
object_count = int(policy)
|
|
|
|
bytes_used = int(policy) * 10
|
|
|
|
broker.put_container('c-%s' % policy.name, put_timestamp,
|
|
|
|
delete_timestamp, object_count, bytes_used,
|
|
|
|
int(policy))
|
|
|
|
total_containers += 1
|
|
|
|
total_objects += object_count
|
|
|
|
total_bytes += bytes_used
|
|
|
|
expected = HeaderKeyDict({
|
|
|
|
'X-Account-Container-Count': total_containers,
|
|
|
|
'X-Account-Object-Count': total_objects,
|
|
|
|
'X-Account-Bytes-Used': total_bytes,
|
|
|
|
'X-Timestamp': Timestamp(now).normal,
|
|
|
|
'X-PUT-Timestamp': Timestamp(now).normal,
|
|
|
|
})
|
|
|
|
for policy in POLICIES:
|
|
|
|
prefix = 'X-Account-Storage-Policy-%s-' % policy.name
|
2014-09-11 06:55:45 -07:00
|
|
|
expected[prefix + 'Container-Count'] = 1
|
2014-06-10 22:17:47 -07:00
|
|
|
expected[prefix + 'Object-Count'] = int(policy)
|
|
|
|
expected[prefix + 'Bytes-Used'] = int(policy) * 10
|
|
|
|
resp_headers = utils.get_response_headers(broker)
|
2014-09-11 06:55:45 -07:00
|
|
|
per_policy_container_headers = [
|
|
|
|
h for h in resp_headers if
|
|
|
|
h.lower().startswith('x-account-storage-policy-') and
|
|
|
|
h.lower().endswith('-container-count')]
|
|
|
|
self.assertTrue(per_policy_container_headers)
|
|
|
|
for key, value in resp_headers.items():
|
|
|
|
expected_value = expected.pop(key)
|
|
|
|
self.assertEqual(expected_value, str(value),
|
|
|
|
'value for %r was %r not %r' % (
|
|
|
|
key, value, expected_value))
|
|
|
|
self.assertFalse(expected)
|
|
|
|
|
|
|
|
@patch_policies
|
|
|
|
def test_get_response_headers_with_legacy_data(self):
|
2022-07-07 17:27:49 +10:00
|
|
|
broker = backend.AccountBroker(self.db_path, account='a')
|
2014-09-11 06:55:45 -07:00
|
|
|
now = time.time()
|
|
|
|
with mock.patch('time.time', new=lambda: now):
|
|
|
|
broker.initialize(Timestamp(now).internal)
|
|
|
|
# add some container data
|
|
|
|
ts = (Timestamp(t).internal for t in itertools.count(int(now)))
|
|
|
|
total_containers = 0
|
|
|
|
total_objects = 0
|
|
|
|
total_bytes = 0
|
|
|
|
for policy in POLICIES:
|
2015-06-15 22:10:45 +05:30
|
|
|
delete_timestamp = next(ts)
|
|
|
|
put_timestamp = next(ts)
|
2014-09-11 06:55:45 -07:00
|
|
|
object_count = int(policy)
|
|
|
|
bytes_used = int(policy) * 10
|
|
|
|
broker.put_container('c-%s' % policy.name, put_timestamp,
|
|
|
|
delete_timestamp, object_count, bytes_used,
|
|
|
|
int(policy))
|
|
|
|
total_containers += 1
|
|
|
|
total_objects += object_count
|
|
|
|
total_bytes += bytes_used
|
|
|
|
expected = HeaderKeyDict({
|
|
|
|
'X-Account-Container-Count': total_containers,
|
|
|
|
'X-Account-Object-Count': total_objects,
|
|
|
|
'X-Account-Bytes-Used': total_bytes,
|
|
|
|
'X-Timestamp': Timestamp(now).normal,
|
|
|
|
'X-PUT-Timestamp': Timestamp(now).normal,
|
|
|
|
})
|
|
|
|
for policy in POLICIES:
|
|
|
|
prefix = 'X-Account-Storage-Policy-%s-' % policy.name
|
|
|
|
expected[prefix + 'Object-Count'] = int(policy)
|
|
|
|
expected[prefix + 'Bytes-Used'] = int(policy) * 10
|
|
|
|
orig_policy_stats = broker.get_policy_stats
|
|
|
|
|
|
|
|
def stub_policy_stats(*args, **kwargs):
|
|
|
|
policy_stats = orig_policy_stats(*args, **kwargs)
|
|
|
|
for stats in policy_stats.values():
|
|
|
|
# legacy db's won't return container_count
|
|
|
|
del stats['container_count']
|
|
|
|
return policy_stats
|
|
|
|
broker.get_policy_stats = stub_policy_stats
|
|
|
|
resp_headers = utils.get_response_headers(broker)
|
|
|
|
per_policy_container_headers = [
|
|
|
|
h for h in resp_headers if
|
|
|
|
h.lower().startswith('x-account-storage-policy-') and
|
|
|
|
h.lower().endswith('-container-count')]
|
|
|
|
self.assertFalse(per_policy_container_headers)
|
2014-06-10 22:17:47 -07:00
|
|
|
for key, value in resp_headers.items():
|
|
|
|
expected_value = expected.pop(key)
|
|
|
|
self.assertEqual(expected_value, str(value),
|
|
|
|
'value for %r was %r not %r' % (
|
|
|
|
key, value, expected_value))
|
|
|
|
self.assertFalse(expected)
|
2019-09-13 12:25:24 -05:00
|
|
|
|
|
|
|
def test_account_listing_response(self):
|
|
|
|
req = Request.blank('')
|
|
|
|
now = time.time()
|
|
|
|
with mock.patch('time.time', new=lambda: now):
|
|
|
|
resp = utils.account_listing_response('a', req, 'text/plain')
|
|
|
|
self.assertEqual(resp.status_int, 204)
|
|
|
|
expected = HeaderKeyDict({
|
|
|
|
'Content-Type': 'text/plain; charset=utf-8',
|
|
|
|
'X-Account-Container-Count': 0,
|
|
|
|
'X-Account-Object-Count': 0,
|
|
|
|
'X-Account-Bytes-Used': 0,
|
|
|
|
'X-Timestamp': Timestamp(now).normal,
|
|
|
|
'X-PUT-Timestamp': Timestamp(now).normal,
|
|
|
|
})
|
|
|
|
self.assertEqual(expected, resp.headers)
|
|
|
|
self.assertEqual(b'', resp.body)
|
|
|
|
|
|
|
|
@patch_policies([StoragePolicy(0, 'zero', is_default=True)])
|
|
|
|
def test_account_listing_reserved_names(self):
|
2022-07-07 17:27:49 +10:00
|
|
|
broker = backend.AccountBroker(self.db_path, account='a')
|
2019-09-13 12:25:24 -05:00
|
|
|
put_timestamp = next(self.ts)
|
|
|
|
now = time.time()
|
|
|
|
with mock.patch('time.time', new=lambda: now):
|
|
|
|
broker.initialize(put_timestamp.internal)
|
|
|
|
container_timestamp = next(self.ts)
|
|
|
|
broker.put_container(get_reserved_name('foo'),
|
|
|
|
container_timestamp.internal, 0, 10, 100, 0)
|
|
|
|
|
|
|
|
req = Request.blank('')
|
|
|
|
resp = utils.account_listing_response(
|
|
|
|
'a', req, 'application/json', broker)
|
|
|
|
self.assertEqual(resp.status_int, 200)
|
|
|
|
expected = HeaderKeyDict({
|
|
|
|
'Content-Type': 'application/json; charset=utf-8',
|
|
|
|
'Content-Length': 2,
|
|
|
|
'X-Account-Container-Count': 1,
|
|
|
|
'X-Account-Object-Count': 10,
|
|
|
|
'X-Account-Bytes-Used': 100,
|
|
|
|
'X-Timestamp': Timestamp(now).normal,
|
|
|
|
'X-PUT-Timestamp': put_timestamp.normal,
|
|
|
|
'X-Account-Storage-Policy-Zero-Container-Count': 1,
|
|
|
|
'X-Account-Storage-Policy-Zero-Object-Count': 10,
|
|
|
|
'X-Account-Storage-Policy-Zero-Bytes-Used': 100,
|
|
|
|
})
|
|
|
|
self.assertEqual(expected, resp.headers)
|
|
|
|
self.assertEqual(b'[]', resp.body)
|
|
|
|
|
|
|
|
req = Request.blank('', headers={
|
|
|
|
'X-Backend-Allow-Reserved-Names': 'true'})
|
|
|
|
resp = utils.account_listing_response(
|
|
|
|
'a', req, 'application/json', broker)
|
|
|
|
self.assertEqual(resp.status_int, 200)
|
|
|
|
expected = HeaderKeyDict({
|
|
|
|
'Content-Type': 'application/json; charset=utf-8',
|
|
|
|
'Content-Length': 97,
|
|
|
|
'X-Account-Container-Count': 1,
|
|
|
|
'X-Account-Object-Count': 10,
|
|
|
|
'X-Account-Bytes-Used': 100,
|
|
|
|
'X-Timestamp': Timestamp(now).normal,
|
|
|
|
'X-PUT-Timestamp': put_timestamp.normal,
|
|
|
|
'X-Account-Storage-Policy-Zero-Container-Count': 1,
|
|
|
|
'X-Account-Storage-Policy-Zero-Object-Count': 10,
|
|
|
|
'X-Account-Storage-Policy-Zero-Bytes-Used': 100,
|
|
|
|
})
|
|
|
|
self.assertEqual(expected, resp.headers)
|
|
|
|
expected = [{
|
|
|
|
"last_modified": container_timestamp.isoformat,
|
|
|
|
"count": 10,
|
|
|
|
"bytes": 100,
|
|
|
|
"name": get_reserved_name('foo'),
|
|
|
|
}]
|
|
|
|
self.assertEqual(sorted(json.dumps(expected).encode('ascii')),
|
|
|
|
sorted(resp.body))
|