7ef2c28bf3
Now that we no longer support py27, we can use the standard library unittest.mock module instead of the third party mock lib. Change-Id: I4d45ae17f6f84f945f5dd049a929216ce6b6b58e Signed-off-by: Takashi Natsume <takanattie@gmail.com>
470 lines
17 KiB
Python
470 lines
17 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.
|
|
|
|
import io
|
|
import sys
|
|
from unittest import mock
|
|
from urllib import parse
|
|
|
|
from novaclient import base
|
|
from novaclient import exceptions
|
|
from novaclient.tests.unit import fakes
|
|
from novaclient.tests.unit import utils as test_utils
|
|
from novaclient import utils
|
|
from novaclient.v2 import servers
|
|
|
|
UUID = '8e8ec658-c7b0-4243-bdf8-6f7f2952c0d0'
|
|
|
|
|
|
class FakeResource(object):
|
|
NAME_ATTR = 'name'
|
|
|
|
request_ids = fakes.FAKE_REQUEST_ID_LIST
|
|
|
|
def __init__(self, _id, properties):
|
|
self.id = _id
|
|
try:
|
|
self.name = properties['name']
|
|
except KeyError:
|
|
pass
|
|
|
|
def append_request_ids(self, resp):
|
|
pass
|
|
|
|
|
|
class FakeManager(base.ManagerWithFind):
|
|
|
|
resource_class = FakeResource
|
|
|
|
resources = [
|
|
FakeResource('1234', {'name': 'entity_one'}),
|
|
FakeResource('12345', {'name': 'UPPER'}),
|
|
FakeResource('123456', {'name': 'lower'}),
|
|
FakeResource('1234567', {'name': 'Mixed'}),
|
|
FakeResource('12345678', {'name': 'mixed'}),
|
|
FakeResource(UUID, {'name': 'entity_two'}),
|
|
FakeResource('5678', {'name': '9876'}),
|
|
FakeResource('01234', {'name': 'entity_three'})
|
|
]
|
|
|
|
is_alphanum_id_allowed = None
|
|
|
|
def __init__(self, alphanum_id_allowed=False):
|
|
self.is_alphanum_id_allowed = alphanum_id_allowed
|
|
|
|
def get(self, resource_id):
|
|
for resource in self.resources:
|
|
if resource.id == str(resource_id):
|
|
return resource
|
|
raise exceptions.NotFound(resource_id)
|
|
|
|
def list(self):
|
|
return base.ListWithMeta(self.resources, fakes.FAKE_REQUEST_ID_LIST)
|
|
|
|
|
|
class FakeDisplayResource(object):
|
|
NAME_ATTR = 'display_name'
|
|
|
|
def __init__(self, _id, properties):
|
|
self.id = _id
|
|
try:
|
|
self.display_name = properties['display_name']
|
|
except KeyError:
|
|
pass
|
|
|
|
def append_request_ids(self, resp):
|
|
pass
|
|
|
|
|
|
class FakeDisplayManager(FakeManager):
|
|
|
|
resource_class = FakeDisplayResource
|
|
|
|
resources = [
|
|
FakeDisplayResource('4242', {'display_name': 'entity_three'}),
|
|
]
|
|
|
|
|
|
class FindResourceTestCase(test_utils.TestCase):
|
|
|
|
def setUp(self):
|
|
super(FindResourceTestCase, self).setUp()
|
|
self.manager = FakeManager(None)
|
|
|
|
def test_find_none(self):
|
|
"""Test a few non-valid inputs."""
|
|
self.assertRaises(exceptions.CommandError,
|
|
utils.find_resource,
|
|
self.manager,
|
|
'asdf')
|
|
self.assertRaises(exceptions.CommandError,
|
|
utils.find_resource,
|
|
self.manager,
|
|
None)
|
|
self.assertRaises(exceptions.CommandError,
|
|
utils.find_resource,
|
|
self.manager,
|
|
{})
|
|
|
|
def test_find_by_integer_id(self):
|
|
output = utils.find_resource(self.manager, 1234)
|
|
self.assertEqual(output, self.manager.get('1234'))
|
|
|
|
def test_find_by_str_id(self):
|
|
output = utils.find_resource(self.manager, '1234')
|
|
self.assertEqual(output, self.manager.get('1234'))
|
|
|
|
def test_find_by_uuid(self):
|
|
output = utils.find_resource(self.manager, UUID)
|
|
self.assertEqual(output, self.manager.get(UUID))
|
|
|
|
def test_find_by_str_name(self):
|
|
output = utils.find_resource(self.manager, 'entity_one')
|
|
self.assertEqual(output, self.manager.get('1234'))
|
|
|
|
def test_find_by_str_upper_name(self):
|
|
output = utils.find_resource(self.manager, 'UPPER')
|
|
self.assertEqual(output, self.manager.get('12345'))
|
|
|
|
def test_find_by_str_lower_name(self):
|
|
output = utils.find_resource(self.manager, 'lower')
|
|
self.assertEqual(output, self.manager.get('123456'))
|
|
|
|
def test_find_by_str_mix_name(self):
|
|
output = utils.find_resource(self.manager, 'Mixed')
|
|
self.assertEqual(output, self.manager.get('1234567'))
|
|
|
|
def test_find_by_str_lower_name_mixed(self):
|
|
output = utils.find_resource(self.manager, 'mixed')
|
|
self.assertEqual(output, self.manager.get('12345678'))
|
|
|
|
def test_find_by_str_display_name(self):
|
|
display_manager = FakeDisplayManager(None)
|
|
output = utils.find_resource(display_manager, 'entity_three')
|
|
self.assertEqual(output, display_manager.get('4242'))
|
|
|
|
def test_find_in_alphanum_allowed_manager_by_str_id_(self):
|
|
alphanum_manager = FakeManager(True)
|
|
output = utils.find_resource(alphanum_manager, '01234')
|
|
self.assertEqual(output, alphanum_manager.get('01234'))
|
|
|
|
def test_find_without_wrapping_exception(self):
|
|
alphanum_manager = FakeManager(True)
|
|
self.assertRaises(exceptions.NotFound, utils.find_resource,
|
|
alphanum_manager, 'not_exist', wrap_exception=False)
|
|
res = alphanum_manager.resources[0]
|
|
alphanum_manager.resources.append(res)
|
|
self.assertRaises(exceptions.NoUniqueMatch, utils.find_resource,
|
|
alphanum_manager, res.name, wrap_exception=False)
|
|
|
|
|
|
class _FakeResult(object):
|
|
def __init__(self, name, value):
|
|
self.name = name
|
|
self.value = value
|
|
|
|
|
|
class PrintResultTestCase(test_utils.TestCase):
|
|
@mock.patch('sys.stdout', io.StringIO())
|
|
def test_print_dict(self):
|
|
dict = {'key': 'value'}
|
|
utils.print_dict(dict)
|
|
self.assertEqual('+----------+-------+\n'
|
|
'| Property | Value |\n'
|
|
'+----------+-------+\n'
|
|
'| key | value |\n'
|
|
'+----------+-------+\n',
|
|
sys.stdout.getvalue())
|
|
|
|
@mock.patch('sys.stdout', io.StringIO())
|
|
def test_print_dict_wrap(self):
|
|
dict = {'key1': 'not wrapped',
|
|
'key2': 'this will be wrapped'}
|
|
utils.print_dict(dict, wrap=16)
|
|
self.assertEqual('+----------+--------------+\n'
|
|
'| Property | Value |\n'
|
|
'+----------+--------------+\n'
|
|
'| key1 | not wrapped |\n'
|
|
'| key2 | this will be |\n'
|
|
'| | wrapped |\n'
|
|
'+----------+--------------+\n',
|
|
sys.stdout.getvalue())
|
|
|
|
@mock.patch('sys.stdout', io.StringIO())
|
|
def test_print_list_sort_by_str(self):
|
|
objs = [_FakeResult("k1", 1),
|
|
_FakeResult("k3", 2),
|
|
_FakeResult("k2", 3)]
|
|
|
|
utils.print_list(objs, ["Name", "Value"], sortby_index=0)
|
|
|
|
self.assertEqual('+------+-------+\n'
|
|
'| Name | Value |\n'
|
|
'+------+-------+\n'
|
|
'| k1 | 1 |\n'
|
|
'| k2 | 3 |\n'
|
|
'| k3 | 2 |\n'
|
|
'+------+-------+\n',
|
|
sys.stdout.getvalue())
|
|
|
|
@mock.patch('sys.stdout', io.StringIO())
|
|
def test_print_list_sort_by_integer(self):
|
|
objs = [_FakeResult("k1", 1),
|
|
_FakeResult("k3", 2),
|
|
_FakeResult("k2", 3)]
|
|
|
|
utils.print_list(objs, ["Name", "Value"], sortby_index=1)
|
|
|
|
self.assertEqual('+------+-------+\n'
|
|
'| Name | Value |\n'
|
|
'+------+-------+\n'
|
|
'| k1 | 1 |\n'
|
|
'| k3 | 2 |\n'
|
|
'| k2 | 3 |\n'
|
|
'+------+-------+\n',
|
|
sys.stdout.getvalue())
|
|
|
|
@mock.patch('sys.stdout', io.StringIO())
|
|
def test_print_unicode_list(self):
|
|
objs = [_FakeResult("k", '\u2026')]
|
|
utils.print_list(objs, ["Name", "Value"])
|
|
s = '\u2026'
|
|
self.assertEqual('+------+-------+\n'
|
|
'| Name | Value |\n'
|
|
'+------+-------+\n'
|
|
'| k | %s |\n'
|
|
'+------+-------+\n' % s,
|
|
sys.stdout.getvalue())
|
|
|
|
# without sorting
|
|
@mock.patch('sys.stdout', io.StringIO())
|
|
def test_print_list_sort_by_none(self):
|
|
objs = [_FakeResult("k1", 1),
|
|
_FakeResult("k3", 3),
|
|
_FakeResult("k2", 2)]
|
|
|
|
utils.print_list(objs, ["Name", "Value"], sortby_index=None)
|
|
|
|
self.assertEqual('+------+-------+\n'
|
|
'| Name | Value |\n'
|
|
'+------+-------+\n'
|
|
'| k1 | 1 |\n'
|
|
'| k3 | 3 |\n'
|
|
'| k2 | 2 |\n'
|
|
'+------+-------+\n',
|
|
sys.stdout.getvalue())
|
|
|
|
@mock.patch('sys.stdout', io.StringIO())
|
|
def test_print_dict_dictionary(self):
|
|
dict = {'k': {'foo': 'bar'}}
|
|
utils.print_dict(dict)
|
|
self.assertEqual('+----------+----------------+\n'
|
|
'| Property | Value |\n'
|
|
'+----------+----------------+\n'
|
|
'| k | {"foo": "bar"} |\n'
|
|
'+----------+----------------+\n',
|
|
sys.stdout.getvalue())
|
|
|
|
@mock.patch('sys.stdout', io.StringIO())
|
|
def test_print_dict_list_dictionary(self):
|
|
dict = {'k': [{'foo': 'bar'}]}
|
|
utils.print_dict(dict)
|
|
self.assertEqual('+----------+------------------+\n'
|
|
'| Property | Value |\n'
|
|
'+----------+------------------+\n'
|
|
'| k | [{"foo": "bar"}] |\n'
|
|
'+----------+------------------+\n',
|
|
sys.stdout.getvalue())
|
|
|
|
@mock.patch('sys.stdout', io.StringIO())
|
|
def test_print_dict_list(self):
|
|
dict = {'k': ['foo', 'bar']}
|
|
utils.print_dict(dict)
|
|
self.assertEqual('+----------+----------------+\n'
|
|
'| Property | Value |\n'
|
|
'+----------+----------------+\n'
|
|
'| k | ["foo", "bar"] |\n'
|
|
'+----------+----------------+\n',
|
|
sys.stdout.getvalue())
|
|
|
|
@mock.patch('sys.stdout', io.StringIO())
|
|
def test_print_large_dict_list(self):
|
|
dict = {'k': ['foo1', 'bar1', 'foo2', 'bar2',
|
|
'foo3', 'bar3', 'foo4', 'bar4']}
|
|
utils.print_dict(dict, wrap=40)
|
|
self.assertEqual(
|
|
'+----------+------------------------------------------+\n'
|
|
'| Property | Value |\n'
|
|
'+----------+------------------------------------------+\n'
|
|
'| k | ["foo1", "bar1", "foo2", "bar2", "foo3", |\n'
|
|
'| | "bar3", "foo4", "bar4"] |\n'
|
|
'+----------+------------------------------------------+\n',
|
|
sys.stdout.getvalue())
|
|
|
|
@mock.patch('sys.stdout', io.StringIO())
|
|
def test_print_unicode_dict(self):
|
|
dict = {'k': '\u2026'}
|
|
utils.print_dict(dict)
|
|
s = '\u2026'
|
|
self.assertEqual('+----------+-------+\n'
|
|
'| Property | Value |\n'
|
|
'+----------+-------+\n'
|
|
'| k | %s |\n'
|
|
'+----------+-------+\n' % s,
|
|
sys.stdout.getvalue())
|
|
|
|
|
|
class FlattenTestCase(test_utils.TestCase):
|
|
def test_flattening(self):
|
|
squashed = utils.flatten_dict(
|
|
{'a1': {'b1': 1234,
|
|
'b2': 'string',
|
|
'b3': set((1, 2, 3)),
|
|
'b4': {'c1': ['l', 'l', ['l']],
|
|
'c2': 'string'}},
|
|
'a2': ['l'],
|
|
'a3': ('t',),
|
|
'a4': {}})
|
|
|
|
self.assertEqual({'a1_b1': 1234,
|
|
'a1_b2': 'string',
|
|
'a1_b3': set([1, 2, 3]),
|
|
'a1_b4_c1': ['l', 'l', ['l']],
|
|
'a1_b4_c2': 'string',
|
|
'a2': ['l'],
|
|
'a3': ('t',),
|
|
'a4': {}},
|
|
squashed)
|
|
|
|
def test_pretty_choice_dict(self):
|
|
d = {}
|
|
r = utils.pretty_choice_dict(d)
|
|
self.assertEqual("", r)
|
|
|
|
d = {"k1": "v1",
|
|
"k2": "v2",
|
|
"k3": "v3"}
|
|
r = utils.pretty_choice_dict(d)
|
|
self.assertEqual("'k1=v1', 'k2=v2', 'k3=v3'", r)
|
|
|
|
|
|
class ValidationsTestCase(test_utils.TestCase):
|
|
def test_validate_flavor_metadata_keys_with_valid_keys(self):
|
|
valid_keys = ['key1', 'month.price', 'I-Am:AK-ey.01-', 'spaces and _']
|
|
utils.validate_flavor_metadata_keys(valid_keys)
|
|
|
|
def test_validate_flavor_metadata_keys_with_invalid_keys(self):
|
|
invalid_keys = ['/1', '?1', '%1', '<', '>', '\1']
|
|
for key in invalid_keys:
|
|
try:
|
|
utils.validate_flavor_metadata_keys([key])
|
|
self.fail("Invalid key passed validation: %s" % key)
|
|
except exceptions.CommandError as ce:
|
|
self.assertIn(key, str(ce))
|
|
|
|
|
|
class DoActionOnManyTestCase(test_utils.TestCase):
|
|
|
|
def _test_do_action_on_many(self, side_effect, fail):
|
|
action = mock.Mock(side_effect=side_effect)
|
|
|
|
if fail:
|
|
self.assertRaises(exceptions.CommandError,
|
|
utils.do_action_on_many,
|
|
action, [1, 2], 'success with %s', 'error')
|
|
else:
|
|
utils.do_action_on_many(action, [1, 2], 'success with %s', 'error')
|
|
action.assert_has_calls([mock.call(1), mock.call(2)])
|
|
|
|
def test_do_action_on_many_success(self):
|
|
self._test_do_action_on_many([None, None], fail=False)
|
|
|
|
def test_do_action_on_many_first_fails(self):
|
|
self._test_do_action_on_many([Exception(), None], fail=True)
|
|
|
|
def test_do_action_on_many_last_fails(self):
|
|
self._test_do_action_on_many([None, Exception()], fail=True)
|
|
|
|
@mock.patch('sys.stdout', new_callable=io.StringIO)
|
|
def _test_do_action_on_many_resource_string(
|
|
self, resource, expected_string, mock_stdout):
|
|
utils.do_action_on_many(mock.Mock(), [resource], 'success with %s',
|
|
'error')
|
|
self.assertIn('success with %s' % expected_string,
|
|
mock_stdout.getvalue())
|
|
|
|
def test_do_action_on_many_resource_string_with_str(self):
|
|
self._test_do_action_on_many_resource_string('resource1', 'resource1')
|
|
|
|
def test_do_action_on_many_resource_string_with_human_id(self):
|
|
resource = servers.Server(None, {'name': 'resource1'})
|
|
self._test_do_action_on_many_resource_string(resource, 'resource1')
|
|
|
|
def test_do_action_on_many_resource_string_with_id(self):
|
|
resource = servers.Server(None, {'id': UUID})
|
|
self._test_do_action_on_many_resource_string(resource, UUID)
|
|
|
|
def test_do_action_on_many_resource_string_with_id_and_human_id(self):
|
|
resource = servers.Server(None, {'name': 'resource1', 'id': UUID})
|
|
self._test_do_action_on_many_resource_string(resource,
|
|
'resource1 (%s)' % UUID)
|
|
|
|
|
|
class RecordTimeTestCase(test_utils.TestCase):
|
|
|
|
def test_record_time(self):
|
|
times = []
|
|
|
|
with utils.record_time(times, True, 'a', 'b'):
|
|
pass
|
|
self.assertEqual(1, len(times))
|
|
self.assertEqual(3, len(times[0]))
|
|
self.assertEqual('a b', times[0][0])
|
|
self.assertIsInstance(times[0][1], float)
|
|
self.assertIsInstance(times[0][2], float)
|
|
|
|
times = []
|
|
with utils.record_time(times, False, 'x'):
|
|
pass
|
|
self.assertEqual(0, len(times))
|
|
|
|
|
|
class PrepareQueryStringTestCase(test_utils.TestCase):
|
|
|
|
def setUp(self):
|
|
super(PrepareQueryStringTestCase, self).setUp()
|
|
self.ustr = b'?\xd0\xbf=1&\xd1\x80=2'
|
|
# in py3 real unicode symbols will be urlencoded
|
|
self.ustr = self.ustr.decode('utf8')
|
|
self.cases = (
|
|
({}, ''),
|
|
(None, ''),
|
|
({'2': 2, '10': 1}, '?10=1&2=2'),
|
|
({'abc': 1, 'abc1': 2}, '?abc=1&abc1=2'),
|
|
({b'\xd0\xbf': 1, b'\xd1\x80': 2}, self.ustr),
|
|
({(1, 2): '1', (3, 4): '2'}, '?(1, 2)=1&(3, 4)=2')
|
|
)
|
|
|
|
def test_convert_dict_to_string(self):
|
|
for case in self.cases:
|
|
self.assertEqual(
|
|
case[1],
|
|
parse.unquote_plus(utils.prepare_query_string(case[0])))
|
|
|
|
def test_get_url_with_filter(self):
|
|
url = '/fake'
|
|
for case in self.cases:
|
|
self.assertEqual(
|
|
'%s%s' % (url, case[1]),
|
|
parse.unquote_plus(utils.get_url_with_filter(url, case[0])))
|