266 lines
10 KiB
Python
266 lines
10 KiB
Python
# Copyright 2013 OpenStack Foundation
|
|
# All Rights Reserved.
|
|
#
|
|
# 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 mock
|
|
import six
|
|
|
|
from ceilometerclient.common import utils
|
|
from ceilometerclient.tests.unit import utils as test_utils
|
|
|
|
|
|
class UtilsTest(test_utils.BaseTestCase):
|
|
|
|
def test_prettytable(self):
|
|
class Struct(object):
|
|
def __init__(self, **entries):
|
|
self.__dict__.update(entries)
|
|
|
|
# test that the prettytable output is wellformatted (left-aligned)
|
|
with mock.patch('sys.stdout', new=six.StringIO()) as stdout:
|
|
utils.print_dict({'K': 'k', 'Key': 'Value'})
|
|
self.assertEqual('''\
|
|
+----------+-------+
|
|
| Property | Value |
|
|
+----------+-------+
|
|
| K | k |
|
|
| Key | Value |
|
|
+----------+-------+
|
|
''', stdout.getvalue())
|
|
|
|
with mock.patch('sys.stdout', new=six.StringIO()) as stdout:
|
|
utils.print_dict({'alarm_id': '262567fd-d79a-4bbb-a9d0-59d879b6',
|
|
'name': u'\u6d4b\u8bd5',
|
|
'description': u'\u6d4b\u8bd5',
|
|
'state': 'insufficient data',
|
|
'repeat_actions': 'False',
|
|
'type': 'threshold',
|
|
'threshold': '1.0',
|
|
'statistic': 'avg',
|
|
'time_constraints': '[{name: c1,'
|
|
'\\n description: test,'
|
|
'\\n start: 0 18 * * *,'
|
|
'\\n duration: 1,'
|
|
'\\n timezone: US}]'},
|
|
wrap=72)
|
|
expected = u'''\
|
|
+------------------+----------------------------------+
|
|
| Property | Value |
|
|
+------------------+----------------------------------+
|
|
| alarm_id | 262567fd-d79a-4bbb-a9d0-59d879b6 |
|
|
| description | \u6d4b\u8bd5 |
|
|
| name | \u6d4b\u8bd5 |
|
|
| repeat_actions | False |
|
|
| state | insufficient data |
|
|
| statistic | avg |
|
|
| threshold | 1.0 |
|
|
| time_constraints | [{name: c1, |
|
|
| | description: test, |
|
|
| | start: 0 18 * * *, |
|
|
| | duration: 1, |
|
|
| | timezone: US}] |
|
|
| type | threshold |
|
|
+------------------+----------------------------------+
|
|
'''
|
|
# py2 prints str type, py3 prints unicode type
|
|
if six.PY2:
|
|
expected = expected.encode('utf-8')
|
|
self.assertEqual(expected, stdout.getvalue())
|
|
|
|
def test_print_list(self):
|
|
class Foo(object):
|
|
def __init__(self, one, two, three):
|
|
self.one = one
|
|
self.two = two
|
|
self.three = three
|
|
|
|
foo_list = [
|
|
Foo(10, 'a', 'B'),
|
|
Foo(8, 'c', 'c'),
|
|
Foo(12, '0', 'Z')]
|
|
|
|
def do_print_list(sortby):
|
|
with mock.patch('sys.stdout', new=six.StringIO()) as stdout:
|
|
utils.print_list(foo_list,
|
|
['one', 'two', 'three'],
|
|
['1st', '2nd', '3rd'],
|
|
{'one': lambda o: o.one * 10},
|
|
sortby)
|
|
return stdout.getvalue()
|
|
|
|
printed = do_print_list(None)
|
|
self.assertEqual('''\
|
|
+-----+-----+-----+
|
|
| 1st | 2nd | 3rd |
|
|
+-----+-----+-----+
|
|
| 100 | a | B |
|
|
| 80 | c | c |
|
|
| 120 | 0 | Z |
|
|
+-----+-----+-----+
|
|
''', printed)
|
|
|
|
printed = do_print_list(0)
|
|
self.assertEqual('''\
|
|
+-----+-----+-----+
|
|
| 1st | 2nd | 3rd |
|
|
+-----+-----+-----+
|
|
| 80 | c | c |
|
|
| 100 | a | B |
|
|
| 120 | 0 | Z |
|
|
+-----+-----+-----+
|
|
''', printed)
|
|
|
|
printed = do_print_list(1)
|
|
self.assertEqual('''\
|
|
+-----+-----+-----+
|
|
| 1st | 2nd | 3rd |
|
|
+-----+-----+-----+
|
|
| 120 | 0 | Z |
|
|
| 100 | a | B |
|
|
| 80 | c | c |
|
|
+-----+-----+-----+
|
|
''', printed)
|
|
|
|
def test_args_array_to_dict(self):
|
|
my_args = {
|
|
'matching_metadata': ['metadata.key=metadata_value'],
|
|
'other': 'value'
|
|
}
|
|
cleaned_dict = utils.args_array_to_dict(my_args,
|
|
"matching_metadata")
|
|
self.assertEqual({
|
|
'matching_metadata': {'metadata.key': 'metadata_value'},
|
|
'other': 'value'
|
|
}, cleaned_dict)
|
|
|
|
def test_args_array_to_list_of_dicts(self):
|
|
starts = ['0 11 * * *', '"0 11 * * *"', '\'0 11 * * *\'']
|
|
timezones = [None, 'US/Eastern', '"US/Eastern"', '\'US/Eastern\'']
|
|
descs = [None, 'de sc', '"de sc"', '\'de sc\'']
|
|
for start, tz, desc in itertools.product(starts, timezones, descs):
|
|
my_args = {
|
|
'time_constraints': ['name=const1;start=%s;duration=1'
|
|
% start],
|
|
'other': 'value'
|
|
}
|
|
expected = {
|
|
'time_constraints': [dict(name='const1',
|
|
start='0 11 * * *',
|
|
duration='1')],
|
|
'other': 'value'
|
|
}
|
|
if tz:
|
|
my_args['time_constraints'][0] += ';timezone=%s' % tz
|
|
expected['time_constraints'][0]['timezone'] = 'US/Eastern'
|
|
if desc:
|
|
my_args['time_constraints'][0] += ';description=%s' % desc
|
|
expected['time_constraints'][0]['description'] = 'de sc'
|
|
|
|
cleaned = utils.args_array_to_list_of_dicts(my_args,
|
|
'time_constraints')
|
|
self.assertEqual(expected, cleaned)
|
|
|
|
def test_key_with_slash_to_nested_dict(self):
|
|
my_args = {
|
|
'combination_rule/alarm_ids': ['id1', 'id2'],
|
|
'combination_rule/operator': 'and',
|
|
'threshold_rule/threshold': 400,
|
|
'threshold_rule/statictic': 'avg',
|
|
'threshold_rule/comparison_operator': 'or',
|
|
}
|
|
nested_dict = utils.key_with_slash_to_nested_dict(my_args)
|
|
self.assertEqual({
|
|
'combination_rule': {'alarm_ids': ['id1', 'id2'],
|
|
'operator': 'and'},
|
|
'threshold_rule': {'threshold': 400,
|
|
'statictic': 'avg',
|
|
'comparison_operator': 'or'},
|
|
}, nested_dict)
|
|
|
|
def test_arg(self):
|
|
@utils.arg(help="not_required_no_default.")
|
|
def not_required_no_default():
|
|
pass
|
|
_, args = not_required_no_default.__dict__['arguments'][0]
|
|
self.assertEqual("not_required_no_default.", args['help'])
|
|
|
|
@utils.arg(required=True, help="required_no_default.")
|
|
def required_no_default():
|
|
pass
|
|
_, args = required_no_default.__dict__['arguments'][0]
|
|
self.assertEqual("required_no_default. Required.", args['help'])
|
|
|
|
@utils.arg(default=42, help="not_required_default.")
|
|
def not_required_default():
|
|
pass
|
|
_, args = not_required_default.__dict__['arguments'][0]
|
|
self.assertEqual("not_required_default. Defaults to 42.", args['help'])
|
|
|
|
def test_merge_nested_dict(self):
|
|
dest = {'key': 'value',
|
|
'nested': {'key2': 'value2',
|
|
'key3': 'value3',
|
|
'nested2': {'key': 'value',
|
|
'some': 'thing'}}}
|
|
source = {'key': 'modified',
|
|
'nested': {'key3': 'modified3',
|
|
'nested2': {'key5': 'value5'}}}
|
|
utils.merge_nested_dict(dest, source, depth=1)
|
|
|
|
self.assertEqual({'key': 'modified',
|
|
'nested': {'key2': 'value2',
|
|
'key3': 'modified3',
|
|
'nested2': {'key5': 'value5'}}}, dest)
|
|
|
|
def test_merge_nested_dict_no_depth(self):
|
|
dest = {'key': 'value',
|
|
'nested': {'key2': 'value2',
|
|
'key3': 'value3',
|
|
'nested2': {'key': 'value',
|
|
'some': 'thing'}}}
|
|
source = {'key': 'modified',
|
|
'nested': {'key3': 'modified3',
|
|
'nested2': {'key5': 'value5'}}}
|
|
utils.merge_nested_dict(dest, source)
|
|
|
|
self.assertEqual({'key': 'modified',
|
|
'nested': {'key3': 'modified3',
|
|
'nested2': {'key5': 'value5'}}}, dest)
|
|
|
|
@mock.patch('prettytable.PrettyTable')
|
|
def test_format_nested_list_of_dict(self, pt_mock):
|
|
actual_rows = []
|
|
|
|
def mock_add_row(row):
|
|
actual_rows.append(row)
|
|
|
|
table = mock.Mock()
|
|
table.add_row = mock_add_row
|
|
table.get_string.return_value = "the table"
|
|
|
|
test_data = [
|
|
{'column_1': 'value_11', 'column_2': 'value_21'},
|
|
{'column_1': 'value_12', 'column_2': 'value_22'}
|
|
|
|
]
|
|
columns = ['column_1', 'column_2']
|
|
pt_mock.return_value = table
|
|
|
|
rval = utils.format_nested_list_of_dict(test_data, columns)
|
|
self.assertEqual("the table", rval)
|
|
self.assertEqual([['value_11', 'value_21'], ['value_12', 'value_22']],
|
|
actual_rows)
|