From 4a6eaedf3cecf282ab181fcd154638623d144b03 Mon Sep 17 00:00:00 2001 From: Madhurya <madhurya.jesu@tcs.com> Date: Wed, 12 Aug 2015 10:55:06 +0530 Subject: [PATCH] MemoryUnit Incorrectly normalizes to uppercase As per GNU standard, modified scalar units dictionary in utils.py. Validating scalar unit size and if not followed GNU standard, converting given scalar unit to GNU standard value after displaying a warning message. Modified scalar unit dictionaries in scalarunit.py Added validation for scalar input unit Added testcases in test_utils.py Modified the code to avoid displaying warning message multiple times Change-Id: Ie038e797f0bedb5da8f97e0f4688b961242b9015 --- translator/common/utils.py | 35 ++++++---- translator/tests/test_utils.py | 26 ++++++++ translator/toscalib/dataentity.py | 3 +- translator/toscalib/elements/scalarunit.py | 69 ++++++++++++-------- translator/toscalib/properties.py | 5 +- translator/toscalib/tests/test_scalarunit.py | 17 +++-- 6 files changed, 103 insertions(+), 52 deletions(-) diff --git a/translator/common/utils.py b/translator/common/utils.py index e971a731..96421c4a 100644 --- a/translator/common/utils.py +++ b/translator/common/utils.py @@ -28,10 +28,10 @@ log = logging.getLogger('tosca') class MemoryUnit(object): UNIT_SIZE_DEFAULT = 'B' - UNIT_SIZE_DICT = {'B': 1, 'KB': 1000, 'KIB': 1024, 'MB': 1000000, - 'MIB': 1048576, 'GB': 1000000000, - 'GIB': 1073741824, 'TB': 1000000000000, - 'TIB': 1099511627776} + UNIT_SIZE_DICT = {'B': 1, 'kB': 1000, 'KiB': 1024, 'MB': 1000000, + 'MiB': 1048576, 'GB': 1000000000, + 'GiB': 1073741824, 'TB': 1000000000000, + 'TiB': 1099511627776} @staticmethod def convert_unit_size_to_num(size, unit=None): @@ -42,29 +42,38 @@ class MemoryUnit(object): :param unit: unit to be converted to e.g GB :return: converted number e.g. 1000 for 1 TB size and unit GB """ - if unit: - MemoryUnit.validate_unit(unit) + unit = MemoryUnit.validate_unit(unit) else: unit = MemoryUnit.UNIT_SIZE_DEFAULT - + log.info(_('A memory unit is not provided for size; using the ' + 'default unit %(default)s') % {'default': 'B'}) regex = re.compile('(\d*)\s*(\w*)') result = regex.match(str(size)).groups() if result[1]: - MemoryUnit.validate_unit(result[1]) + unit_size = MemoryUnit.validate_unit(result[1]) converted = int(str_to_num(result[0]) - * MemoryUnit.UNIT_SIZE_DICT[result[1].upper()] + * MemoryUnit.UNIT_SIZE_DICT[unit_size] * math.pow(MemoryUnit.UNIT_SIZE_DICT - [unit.upper()], -1)) + [unit], -1)) + log.info(_('Given size %(size)s is converted to %(num)s ' + '%(unit)s') % {'size': size, + 'num': converted, 'unit': unit}) else: converted = (str_to_num(result[0])) return converted @staticmethod def validate_unit(unit): - if unit.upper() not in MemoryUnit.UNIT_SIZE_DICT.keys(): - msg = _('Provided unit "{0}" is not valid. The valid units are ' - '{1}').format(unit, MemoryUnit.UNIT_SIZE_DICT.keys()) + if unit in MemoryUnit.UNIT_SIZE_DICT.keys(): + return unit + else: + for key in MemoryUnit.UNIT_SIZE_DICT.keys(): + if key.upper() == unit.upper(): + return key + + msg = _('Provided unit "{0}" is not valid. The valid units are' + ' {1}').format(unit, MemoryUnit.UNIT_SIZE_DICT.keys()) raise ValueError(msg) diff --git a/translator/tests/test_utils.py b/translator/tests/test_utils.py index 8cb1d6cd..1a964bde 100644 --- a/translator/tests/test_utils.py +++ b/translator/tests/test_utils.py @@ -51,6 +51,32 @@ class CommonUtilsTest(TestCase): isinstance(err, ValueError)) self.assertEqual(exp_msg, err.__str__()) + def test_unit_size_conversion_to_GNU_standard(self): + unit = 'gB' + standard_unit = 'GB' + converted_unit = self.MemoryUnit.validate_unit(unit) + self.assertEqual(converted_unit, standard_unit) + + unit = 'KB' + standard_unit = 'kB' + converted_unit = self.MemoryUnit.validate_unit(unit) + self.assertEqual(converted_unit, standard_unit) + + unit = 'kb' + standard_unit = 'kB' + converted_unit = self.MemoryUnit.validate_unit(unit) + self.assertEqual(converted_unit, standard_unit) + + unit = 'kB' + standard_unit = 'kB' + converted_unit = self.MemoryUnit.validate_unit(unit) + self.assertEqual(converted_unit, standard_unit) + + unit = 'MIB' + standard_unit = 'MiB' + converted_unit = self.MemoryUnit.validate_unit(unit) + self.assertEqual(converted_unit, standard_unit) + def test_str_to_num_value_error(self): str_to_convert = '55063.000000' expected_output = 55063.0 diff --git a/translator/toscalib/dataentity.py b/translator/toscalib/dataentity.py index a971b831..f703775d 100644 --- a/translator/toscalib/dataentity.py +++ b/translator/toscalib/dataentity.py @@ -119,7 +119,8 @@ class DataEntity(object): elif type == Schema.BOOLEAN: return validateutils.validate_boolean(value) elif type == Schema.TIMESTAMP: - return validateutils.validate_timestamp(value) + validateutils.validate_timestamp(value) + return value elif type == Schema.LIST: validateutils.validate_list(value) if entry_schema: diff --git a/translator/toscalib/elements/scalarunit.py b/translator/toscalib/elements/scalarunit.py index b8d137e9..4b4a8c52 100644 --- a/translator/toscalib/elements/scalarunit.py +++ b/translator/toscalib/elements/scalarunit.py @@ -10,11 +10,14 @@ # License for the specific language governing permissions and limitations # under the License. +import logging import re from translator.toscalib.utils.gettextutils import _ from translator.toscalib.utils import validateutils +log = logging.getLogger('tosca') + class ScalarUnit(object): '''Parent class for scalar-unit type.''' @@ -28,23 +31,42 @@ class ScalarUnit(object): def __init__(self, value): self.value = value + def _check_unit_in_scalar_standard_units(self, input_unit): + """Check whether the input unit is following specified standard + + If unit is not following specified standard, convert it to standard + unit after displaying a warning message. + """ + if input_unit in self.SCALAR_UNIT_DICT.keys(): + return input_unit + else: + for key in self.SCALAR_UNIT_DICT.keys(): + if key.upper() == input_unit.upper(): + log.warning(_('Given unit %(unit)s does not follow scalar ' + 'unit standards; using %(key)s instead.') % { + 'unit': input_unit, 'key': key}) + return key + msg = (_('Provided unit "%(unit)s" is not valid. The valid units' + ' are %(valid_units)s') % {'unit': input_unit, + 'valid_units': sorted(self.SCALAR_UNIT_DICT.keys())}) + raise ValueError(msg) + def validate_scalar_unit(self): regex = re.compile('([0-9.]+)\s*(\w+)') try: result = regex.match(str(self.value)).groups() validateutils.str_to_num(result[0]) + scalar_unit = self._check_unit_in_scalar_standard_units(result[1]) + self.value = ' '.join([result[0], scalar_unit]) + return self.value + except Exception: raise ValueError(_('"%s" is not a valid scalar-unit') % self.value) - if result[1].upper() in self.SCALAR_UNIT_DICT.keys(): - return self.value - raise ValueError(_('"%s" is not a valid scalar-unit') % self.value) def get_num_from_scalar_unit(self, unit=None): if unit: - if unit.upper() not in self.SCALAR_UNIT_DICT.keys(): - raise ValueError(_('input unit "%s" is not a valid unit') - % unit) + unit = self._check_unit_in_scalar_standard_units(unit) else: unit = self.SCALAR_UNIT_DEFAULT self.validate_scalar_unit() @@ -52,45 +74,34 @@ class ScalarUnit(object): regex = re.compile('([0-9.]+)\s*(\w+)') result = regex.match(str(self.value)).groups() converted = (float(validateutils.str_to_num(result[0])) - * self.SCALAR_UNIT_DICT[result[1].upper()] - / self.SCALAR_UNIT_DICT[unit.upper()]) + * self.SCALAR_UNIT_DICT[result[1]] + / self.SCALAR_UNIT_DICT[unit]) if converted - int(converted) < 0.0000000000001: converted = int(converted) return converted - def get_unit_from_scalar_unit(self, unit=None): - if unit: - if unit.upper() not in self.SCALAR_UNIT_DICT.keys(): - raise ValueError(_('input unit "%s" is not a valid unit') - % unit) - return unit - else: - regex = re.compile('([0-9.]+)\s*(\w+)') - result = regex.match(str(self.value)).groups() - return result[1].upper() - class ScalarUnit_Size(ScalarUnit): SCALAR_UNIT_DEFAULT = 'B' - SCALAR_UNIT_DICT = {'B': 1, 'KB': 1000, 'KIB': 1024, 'MB': 1000000, - 'MIB': 1048576, 'GB': 1000000000, - 'GIB': 1073741824, 'TB': 1000000000000, - 'TIB': 1099511627776} + SCALAR_UNIT_DICT = {'B': 1, 'kB': 1000, 'KiB': 1024, 'MB': 1000000, + 'MiB': 1048576, 'GB': 1000000000, + 'GiB': 1073741824, 'TB': 1000000000000, + 'TiB': 1099511627776} class ScalarUnit_Time(ScalarUnit): - SCALAR_UNIT_DEFAULT = 'MS' - SCALAR_UNIT_DICT = {'D': 86400, 'H': 3600, 'M': 60, 'S': 1, - 'MS': 0.001, 'US': 0.000001, 'NS': 0.000000001} + SCALAR_UNIT_DEFAULT = 'ms' + SCALAR_UNIT_DICT = {'d': 86400, 'h': 3600, 'm': 60, 's': 1, + 'ms': 0.001, 'us': 0.000001, 'ns': 0.000000001} class ScalarUnit_Frequency(ScalarUnit): - SCALAR_UNIT_DEFAULT = 'GHZ' - SCALAR_UNIT_DICT = {'HZ': 1, 'KHZ': 1000, - 'MHZ': 1000000, 'GHZ': 1000000000} + SCALAR_UNIT_DEFAULT = 'GHz' + SCALAR_UNIT_DICT = {'Hz': 1, 'kHz': 1000, + 'MHz': 1000000, 'GHz': 1000000000} scalarunit_mapping = { diff --git a/translator/toscalib/properties.py b/translator/toscalib/properties.py index 3f4cb181..c3436d01 100644 --- a/translator/toscalib/properties.py +++ b/translator/toscalib/properties.py @@ -65,8 +65,9 @@ class Property(object): if not is_function(self.value): if self.type == Schema.STRING: self.value = str(self.value) - DataEntity.validate_datatype(self.type, self.value, - self.entry_schema, self.custom_def) + self.value = DataEntity.validate_datatype(self.type, self.value, + self.entry_schema, + self.custom_def) self._validate_constraints() def _validate_constraints(self): diff --git a/translator/toscalib/tests/test_scalarunit.py b/translator/toscalib/tests/test_scalarunit.py index 9bb58657..96e14fc7 100644 --- a/translator/toscalib/tests/test_scalarunit.py +++ b/translator/toscalib/tests/test_scalarunit.py @@ -48,7 +48,7 @@ class ScalarUnitPositiveTest(TestCase): mem_size: 1 GB ''', property='mem_size', - expected='1 GB') + expected='1 GB') ), ( # tpl_snippet with mem_size given as number+tiB @@ -62,7 +62,7 @@ class ScalarUnitPositiveTest(TestCase): mem_size: 1tiB ''', property='mem_size', - expected='1tiB') + expected='1 TiB') ), ( # tpl_snippet with mem_size given as number+Spaces+GIB @@ -76,7 +76,7 @@ class ScalarUnitPositiveTest(TestCase): mem_size: 1 GIB ''', property='mem_size', - expected='1 GIB') + expected='1 GiB') ), ( # tpl_snippet with mem_size given as number+Space+tib @@ -90,7 +90,7 @@ class ScalarUnitPositiveTest(TestCase): mem_size: 1 tib ''', property='mem_size', - expected='1 tib') + expected='1 TiB') ), ( 'cpu_frequency_is_float_Space_GHz', @@ -243,7 +243,9 @@ class GetNumFromScalarUnitSizeNegative(TestCase): get_num_from_scalar_unit(self.UserInputUnit)) except Exception as error: self.assertTrue(isinstance(error, ValueError)) - self.assertEqual('input unit "qB" is not a valid unit', + self.assertEqual('Provided unit "qB" is not valid. The valid units' + ' are [\'B\', \'GB\', \'GiB\', \'KiB\', \'MB\',' + ' \'MiB\', \'TB\', \'TiB\', \'kB\']', error.__str__()) @@ -258,7 +260,8 @@ class GetNumFromScalarUnitFrequencyNegative(TestCase): get_num_from_scalar_unit(self.UserInputUnit)) except Exception as error: self.assertTrue(isinstance(error, ValueError)) - self.assertEqual('input unit "Jz" is not a valid unit', + self.assertEqual('Provided unit "Jz" is not valid. The valid' + ' units are [\'GHz\', \'Hz\', \'MHz\', \'kHz\']', error.__str__()) @@ -273,7 +276,7 @@ class GetNumFromScalarUnitTimeNegative(TestCase): get_num_from_scalar_unit(self.UserInputUnit)) except Exception as error: self.assertTrue(isinstance(error, ValueError)) - self.assertEqual('input unit "Jz" is not a valid unit', + self.assertEqual('"Jz" is not a valid scalar-unit', error.__str__())