# # 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])))