856c15539a
Test compares cluster info to hardcoded expected data and wasn't sorting the two sets of things being compared leading to some sporadic unit test failures. Change-Id: I3ef98260a62c15d06ba8cc196196d4e90abca3f0
284 lines
12 KiB
Python
284 lines
12 KiB
Python
# 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.
|
|
|
|
"""Tests for swift.cli.info"""
|
|
|
|
import os
|
|
import unittest
|
|
import cPickle as pickle
|
|
import mock
|
|
from cStringIO import StringIO
|
|
from contextlib import closing
|
|
from gzip import GzipFile
|
|
from shutil import rmtree
|
|
from tempfile import mkdtemp
|
|
|
|
from swift.common import ring, utils
|
|
from swift.common.swob import Request
|
|
from swift.cli.info import print_db_info_metadata, print_ring_locations, \
|
|
print_info, InfoSystemExit
|
|
from swift.account.server import AccountController
|
|
from swift.container.server import ContainerController
|
|
|
|
|
|
class TestCliInfo(unittest.TestCase):
|
|
|
|
def setUp(self):
|
|
self.orig_hp = utils.HASH_PATH_PREFIX, utils.HASH_PATH_SUFFIX
|
|
utils.HASH_PATH_PREFIX = 'info'
|
|
utils.HASH_PATH_SUFFIX = 'info'
|
|
self.testdir = os.path.join(mkdtemp(), 'tmp_test_cli_info')
|
|
utils.mkdirs(self.testdir)
|
|
rmtree(self.testdir)
|
|
utils.mkdirs(os.path.join(self.testdir, 'sda1'))
|
|
utils.mkdirs(os.path.join(self.testdir, 'sda1', 'tmp'))
|
|
utils.mkdirs(os.path.join(self.testdir, 'sdb1'))
|
|
utils.mkdirs(os.path.join(self.testdir, 'sdb1', 'tmp'))
|
|
self.account_ring_path = os.path.join(self.testdir, 'account.ring.gz')
|
|
with closing(GzipFile(self.account_ring_path, 'wb')) as f:
|
|
pickle.dump(ring.RingData([[0, 1, 0, 1], [1, 0, 1, 0]],
|
|
[{'id': 0, 'zone': 0, 'device': 'sda1',
|
|
'ip': '127.0.0.1', 'port': 42},
|
|
{'id': 1, 'zone': 1, 'device': 'sdb1',
|
|
'ip': '127.0.0.2', 'port': 43}], 30),
|
|
f)
|
|
self.container_ring_path = os.path.join(self.testdir,
|
|
'container.ring.gz')
|
|
with closing(GzipFile(self.container_ring_path, 'wb')) as f:
|
|
pickle.dump(ring.RingData([[0, 1, 0, 1], [1, 0, 1, 0]],
|
|
[{'id': 0, 'zone': 0, 'device': 'sda1',
|
|
'ip': '127.0.0.3', 'port': 42},
|
|
{'id': 1, 'zone': 1, 'device': 'sdb1',
|
|
'ip': '127.0.0.4', 'port': 43}], 30),
|
|
f)
|
|
|
|
def tearDown(self):
|
|
utils.HASH_PATH_PREFIX, utils.HASH_PATH_SUFFIX = self.orig_hp
|
|
rmtree(os.path.dirname(self.testdir))
|
|
|
|
def assertRaisesMessage(self, exc, msg, func, *args, **kwargs):
|
|
try:
|
|
func(*args, **kwargs)
|
|
except Exception, e:
|
|
self.assertEqual(msg, str(e))
|
|
self.assertTrue(isinstance(e, exc),
|
|
"Expected %s, got %s" % (exc, type(e)))
|
|
|
|
def test_print_db_info_metadata(self):
|
|
self.assertRaisesMessage(ValueError, 'Wrong DB type',
|
|
print_db_info_metadata, 't', {}, {})
|
|
self.assertRaisesMessage(ValueError, 'DB info is None',
|
|
print_db_info_metadata, 'container', None, {})
|
|
self.assertRaisesMessage(ValueError, 'Info is incomplete',
|
|
print_db_info_metadata, 'container', {}, {})
|
|
|
|
info = dict(
|
|
account='acct',
|
|
created_at=100.1,
|
|
put_timestamp=106.3,
|
|
delete_timestamp=107.9,
|
|
container_count='3',
|
|
object_count='20',
|
|
bytes_used='42')
|
|
info['hash'] = 'abaddeadbeefcafe'
|
|
info['id'] = 'abadf100d0ddba11'
|
|
md = {'x-account-meta-mydata': ('swift', '0000000000.00000'),
|
|
'x-other-something': ('boo', '0000000000.00000')}
|
|
out = StringIO()
|
|
with mock.patch('sys.stdout', out):
|
|
print_db_info_metadata('account', info, md)
|
|
exp_out = '''Path: /acct
|
|
Account: acct
|
|
Account Hash: dc5be2aa4347a22a0fee6bc7de505b47
|
|
Metadata:
|
|
Created at: 1970-01-01 00:01:40.100000 (100.1)
|
|
Put Timestamp: 1970-01-01 00:01:46.300000 (106.3)
|
|
Delete Timestamp: 1970-01-01 00:01:47.900000 (107.9)
|
|
Container Count: 3
|
|
Object Count: 20
|
|
Bytes Used: 42
|
|
Chexor: abaddeadbeefcafe
|
|
UUID: abadf100d0ddba11
|
|
X-Other-Something: boo
|
|
No system metadata found in db file
|
|
User Metadata: {'mydata': 'swift'}'''
|
|
|
|
self.assertEquals(sorted(out.getvalue().strip().split('\n')),
|
|
sorted(exp_out.split('\n')))
|
|
|
|
info = dict(
|
|
account='acct',
|
|
container='cont',
|
|
created_at='0000000100.10000',
|
|
put_timestamp='0000000106.30000',
|
|
delete_timestamp='0000000107.90000',
|
|
object_count='20',
|
|
bytes_used='42',
|
|
reported_put_timestamp='0000010106.30000',
|
|
reported_delete_timestamp='0000010107.90000',
|
|
reported_object_count='20',
|
|
reported_bytes_used='42',
|
|
x_container_foo='bar',
|
|
x_container_bar='goo')
|
|
info['hash'] = 'abaddeadbeefcafe'
|
|
info['id'] = 'abadf100d0ddba11'
|
|
md = {'x-container-sysmeta-mydata': ('swift', '0000000000.00000')}
|
|
out = StringIO()
|
|
with mock.patch('sys.stdout', out):
|
|
print_db_info_metadata('container', info, md)
|
|
exp_out = '''Path: /acct/cont
|
|
Account: acct
|
|
Container: cont
|
|
Container Hash: d49d0ecbb53be1fcc49624f2f7c7ccae
|
|
Metadata:
|
|
Created at: 1970-01-01 00:01:40.100000 (0000000100.10000)
|
|
Put Timestamp: 1970-01-01 00:01:46.300000 (0000000106.30000)
|
|
Delete Timestamp: 1970-01-01 00:01:47.900000 (0000000107.90000)
|
|
Object Count: 20
|
|
Bytes Used: 42
|
|
Reported Put Timestamp: 1970-01-01 02:48:26.300000 (0000010106.30000)
|
|
Reported Delete Timestamp: 1970-01-01 02:48:27.900000 (0000010107.90000)
|
|
Reported Object Count: 20
|
|
Reported Bytes Used: 42
|
|
Chexor: abaddeadbeefcafe
|
|
UUID: abadf100d0ddba11
|
|
X-Container-Bar: goo
|
|
X-Container-Foo: bar
|
|
System Metadata: {'mydata': 'swift'}
|
|
No user metadata found in db file'''
|
|
self.assertEquals(sorted(out.getvalue().strip().split('\n')),
|
|
sorted(exp_out.split('\n')))
|
|
|
|
def test_print_ring_locations(self):
|
|
self.assertRaisesMessage(ValueError, 'None type', print_ring_locations,
|
|
None, 'dir', 'acct')
|
|
self.assertRaisesMessage(ValueError, 'None type', print_ring_locations,
|
|
[], None, 'acct')
|
|
self.assertRaisesMessage(ValueError, 'None type', print_ring_locations,
|
|
[], 'dir', None)
|
|
self.assertRaisesMessage(ValueError, 'Ring error',
|
|
print_ring_locations,
|
|
[], 'dir', 'acct', 'con')
|
|
|
|
out = StringIO()
|
|
with mock.patch('sys.stdout', out):
|
|
acctring = ring.Ring(self.testdir, ring_name='account')
|
|
print_ring_locations(acctring, 'dir', 'acct')
|
|
exp_db2 = os.path.join('/srv', 'node', 'sdb1', 'dir', '3', 'b47',
|
|
'dc5be2aa4347a22a0fee6bc7de505b47',
|
|
'dc5be2aa4347a22a0fee6bc7de505b47.db')
|
|
exp_db1 = os.path.join('/srv', 'node', 'sda1', 'dir', '3', 'b47',
|
|
'dc5be2aa4347a22a0fee6bc7de505b47',
|
|
'dc5be2aa4347a22a0fee6bc7de505b47.db')
|
|
exp_out = ('Ring locations:\n 127.0.0.2:43 - %s\n'
|
|
' 127.0.0.1:42 - %s\n'
|
|
'\nnote: /srv/node is used as default value of `devices`,'
|
|
' the real value is set in the account config file on'
|
|
' each storage node.' % (exp_db2, exp_db1))
|
|
self.assertEquals(out.getvalue().strip(), exp_out)
|
|
|
|
out = StringIO()
|
|
with mock.patch('sys.stdout', out):
|
|
contring = ring.Ring(self.testdir, ring_name='container')
|
|
print_ring_locations(contring, 'dir', 'acct', 'con')
|
|
exp_db4 = os.path.join('/srv', 'node', 'sdb1', 'dir', '1', 'fe6',
|
|
'63e70955d78dfc62821edc07d6ec1fe6',
|
|
'63e70955d78dfc62821edc07d6ec1fe6.db')
|
|
exp_db3 = os.path.join('/srv', 'node', 'sda1', 'dir', '1', 'fe6',
|
|
'63e70955d78dfc62821edc07d6ec1fe6',
|
|
'63e70955d78dfc62821edc07d6ec1fe6.db')
|
|
exp_out = ('Ring locations:\n 127.0.0.4:43 - %s\n'
|
|
' 127.0.0.3:42 - %s\n'
|
|
'\nnote: /srv/node is used as default value of `devices`,'
|
|
' the real value is set in the container config file on'
|
|
' each storage node.' % (exp_db4, exp_db3))
|
|
self.assertEquals(out.getvalue().strip(), exp_out)
|
|
|
|
def test_print_info(self):
|
|
db_file = 'foo'
|
|
self.assertRaises(InfoSystemExit, print_info, 'object', db_file)
|
|
db_file = os.path.join(self.testdir, './acct.db')
|
|
self.assertRaises(InfoSystemExit, print_info, 'account', db_file)
|
|
|
|
controller = AccountController(
|
|
{'devices': self.testdir, 'mount_check': 'false'})
|
|
req = Request.blank('/sda1/1/acct', environ={'REQUEST_METHOD': 'PUT',
|
|
'HTTP_X_TIMESTAMP': '0'})
|
|
resp = req.get_response(controller)
|
|
self.assertEqual(resp.status_int, 201)
|
|
out = StringIO()
|
|
exp_raised = False
|
|
with mock.patch('sys.stdout', out):
|
|
db_file = os.path.join(self.testdir, 'sda1', 'accounts',
|
|
'1', 'b47',
|
|
'dc5be2aa4347a22a0fee6bc7de505b47',
|
|
'dc5be2aa4347a22a0fee6bc7de505b47.db')
|
|
try:
|
|
print_info('account', db_file, swift_dir=self.testdir)
|
|
except Exception:
|
|
exp_raised = True
|
|
if exp_raised:
|
|
self.fail("Unexpected exception raised")
|
|
else:
|
|
self.assertTrue(len(out.getvalue().strip()) > 800)
|
|
|
|
controller = ContainerController(
|
|
{'devices': self.testdir, 'mount_check': 'false'})
|
|
req = Request.blank('/sda1/1/acct/cont',
|
|
environ={'REQUEST_METHOD': 'PUT',
|
|
'HTTP_X_TIMESTAMP': '0'})
|
|
resp = req.get_response(controller)
|
|
self.assertEqual(resp.status_int, 201)
|
|
out = StringIO()
|
|
exp_raised = False
|
|
with mock.patch('sys.stdout', out):
|
|
db_file = os.path.join(self.testdir, 'sda1', 'containers',
|
|
'1', 'cae',
|
|
'd49d0ecbb53be1fcc49624f2f7c7ccae',
|
|
'd49d0ecbb53be1fcc49624f2f7c7ccae.db')
|
|
orig_cwd = os.getcwd()
|
|
try:
|
|
os.chdir(os.path.dirname(db_file))
|
|
print_info('container', os.path.basename(db_file),
|
|
swift_dir='/dev/null')
|
|
except Exception:
|
|
exp_raised = True
|
|
finally:
|
|
os.chdir(orig_cwd)
|
|
if exp_raised:
|
|
self.fail("Unexpected exception raised")
|
|
else:
|
|
self.assertTrue(len(out.getvalue().strip()) > 600)
|
|
|
|
out = StringIO()
|
|
exp_raised = False
|
|
with mock.patch('sys.stdout', out):
|
|
db_file = os.path.join(self.testdir, 'sda1', 'containers',
|
|
'1', 'cae',
|
|
'd49d0ecbb53be1fcc49624f2f7c7ccae',
|
|
'd49d0ecbb53be1fcc49624f2f7c7ccae.db')
|
|
orig_cwd = os.getcwd()
|
|
try:
|
|
os.chdir(os.path.dirname(db_file))
|
|
print_info('account', os.path.basename(db_file),
|
|
swift_dir='/dev/null')
|
|
except InfoSystemExit:
|
|
exp_raised = True
|
|
finally:
|
|
os.chdir(orig_cwd)
|
|
if exp_raised:
|
|
exp_out = 'Does not appear to be a DB of type "account":' \
|
|
' ./d49d0ecbb53be1fcc49624f2f7c7ccae.db'
|
|
self.assertEquals(out.getvalue().strip(), exp_out)
|
|
else:
|
|
self.fail("Expected an InfoSystemExit exception to be raised")
|