From e030c9019a56dce1a988760baafdfd577641b417 Mon Sep 17 00:00:00 2001 From: Shubham Date: Mon, 13 Apr 2020 16:38:20 +0530 Subject: [PATCH] Improve readability of vnf package show command Display show command data in human_readable format for better readability for complex attributes of vnf package like 'softwareImages', 'checksum', '_links' and 'useDefinedData'. Please checkout below link to see the difference in vnf package show response data before and after resolving the issue. http://paste.openstack.org/show/792305/ Change-Id: I4827437461fd42b4da8a90d7f8ef703625c78cf5 --- tackerclient/osc/v1/vnfpkgm/vnf_package.py | 25 ++++++++++++++--- tackerclient/tests/unit/osc/base.py | 16 +++++++++++ .../tests/unit/osc/v1/test_vnf_package.py | 20 +++++++------ .../tests/unit/osc/v1/vnf_package_fakes.py | 28 +++++++++++++------ 4 files changed, 67 insertions(+), 22 deletions(-) diff --git a/tackerclient/osc/v1/vnfpkgm/vnf_package.py b/tackerclient/osc/v1/vnfpkgm/vnf_package.py index 322f0e42..7c1673a7 100644 --- a/tackerclient/osc/v1/vnfpkgm/vnf_package.py +++ b/tackerclient/osc/v1/vnfpkgm/vnf_package.py @@ -17,6 +17,7 @@ from functools import reduce import logging import sys +from cliff import columns as cliff_columns from osc_lib.cli import parseractions from osc_lib.command import command from osc_lib import utils @@ -29,6 +30,18 @@ from tackerclient.osc import utils as tacker_osc_utils LOG = logging.getLogger(__name__) +class FormatComplexDataColumn(cliff_columns.FormattableColumn): + + def human_readable(self): + return tacker_osc_utils.format_dict_with_indention(self._value) + + +formatters = {'softwareImages': FormatComplexDataColumn, + 'checksum': FormatComplexDataColumn, + '_links': FormatComplexDataColumn, + 'userDefinedData': FormatComplexDataColumn} + + _mixed_case_fields = ('usageState', 'onboardingState', 'operationalState', 'vnfProductName', 'softwareImages', 'userDefinedData', 'vnfdId', 'vnfdVersion', 'vnfSoftwareVersion', @@ -87,7 +100,8 @@ class CreateVnfPackage(command.ShowOne): display_columns, columns = _get_columns(vnf_package) data = utils.get_item_properties( sdk_utils.DictModel(vnf_package), - columns, mixed_case_fields=_mixed_case_fields) + columns, formatters=formatters, + mixed_case_fields=_mixed_case_fields) return (display_columns, data) @@ -192,7 +206,8 @@ class ListVnfPackage(command.Lister): long_listing=True) return (headers, (utils.get_dict_properties( - s, columns, mixed_case_fields=_mixed_case_fields, + s, columns, formatters=formatters, + mixed_case_fields=_mixed_case_fields, ) for s in data['vnf_packages'])) @@ -215,7 +230,8 @@ class ShowVnfPackage(command.ShowOne): display_columns, columns = _get_columns(vnf_package) data = utils.get_item_properties( sdk_utils.DictModel(vnf_package), - columns, mixed_case_fields=_mixed_case_fields) + columns, formatters=formatters, + mixed_case_fields=_mixed_case_fields) return (display_columns, data) @@ -452,5 +468,6 @@ class UpdateVnfPackage(command.ShowOne): display_columns, columns = self.get_columns(updated_values) data = utils.get_item_properties( sdk_utils.DictModel(updated_values), - columns, mixed_case_fields=_mixed_case_fields) + columns, formatters=formatters, + mixed_case_fields=_mixed_case_fields) return (display_columns, data) diff --git a/tackerclient/tests/unit/osc/base.py b/tackerclient/tests/unit/osc/base.py index 793d476d..3037ed80 100644 --- a/tackerclient/tests/unit/osc/base.py +++ b/tackerclient/tests/unit/osc/base.py @@ -17,6 +17,8 @@ import mock from requests_mock.contrib import fixture as requests_mock_fixture import testtools +from cliff import columns as cliff_columns + class FixturedTestCase(testtools.TestCase): client_fixture_class = None @@ -51,6 +53,20 @@ class FixturedTestCase(testtools.TestCase): msg = 'method %s should not have been called' % m self.fail(msg) + def assertListItemsEqual(self, expected, actual): + """Assertion based on human_readable values of list items""" + + self.assertEqual(len(expected), len(actual)) + for col_expected, col_actual in zip(expected, actual): + if isinstance(col_actual, tuple): + self.assertListItemsEqual(col_expected, col_actual) + elif isinstance(col_expected, cliff_columns.FormattableColumn): + self.assertIsInstance(col_actual, col_expected.__class__) + self.assertEqual(col_expected.human_readable(), + col_actual.human_readable()) + else: + self.assertEqual(col_expected, col_actual) + class ParserException(Exception): pass diff --git a/tackerclient/tests/unit/osc/v1/test_vnf_package.py b/tackerclient/tests/unit/osc/v1/test_vnf_package.py index be6e6757..c48eaaaa 100644 --- a/tackerclient/tests/unit/osc/v1/test_vnf_package.py +++ b/tackerclient/tests/unit/osc/v1/test_vnf_package.py @@ -104,8 +104,9 @@ class TestCreateVnfPackage(TestVnfPackage): columns, data = (self.create_vnf_package.take_action(parsed_args)) self.assertCountEqual(_get_columns_vnf_package(), columns) - self.assertCountEqual(vnf_package_fakes.get_vnf_package_data(json), - data) + headers, attributes = vnf_package._get_columns(json) + self.assertListItemsEqual(vnf_package_fakes.get_vnf_package_data( + json, columns=attributes), data) @ddt.ddt @@ -186,7 +187,7 @@ class TestListVnfPackage(TestVnfPackage): vnf_package_obj, columns=columns, list_action=True, **kwargs)) self.assertCountEqual(self.get_list_columns(**kwargs), actual_columns) - self.assertCountEqual(expected_data, list(data)) + self.assertListItemsEqual(expected_data, list(data)) def test_take_action_with_exclude_fields(self): parsed_args = self.check_parser( @@ -265,7 +266,7 @@ class TestListVnfPackage(TestVnfPackage): self.assertCountEqual(self.get_list_columns( extra_fields=['Software Images', 'Checksum']), actual_columns) - self.assertCountEqual(expected_data, list(data)) + self.assertListItemsEqual(expected_data, list(data)) @ddt.ddt @@ -288,12 +289,13 @@ class TestShowVnfPackage(TestVnfPackage): self.requests_mock.register_uri('GET', url, json=vnf_package_obj, headers=self.header) columns, data = (self.show_vnf_package.take_action(parsed_args)) - self.assertEqual(sorted(_get_columns_vnf_package( - vnf_package_obj=vnf_package_obj, action='show')), sorted(columns)) self.assertCountEqual(_get_columns_vnf_package( vnf_package_obj=vnf_package_obj, action='show'), columns) - self.assertCountEqual( - vnf_package_fakes.get_vnf_package_data(vnf_package_obj), data) + + headers, attributes = vnf_package._get_columns(vnf_package_obj) + self.assertListItemsEqual( + vnf_package_fakes.get_vnf_package_data(vnf_package_obj, + columns=attributes), data) def test_show_no_options(self): self.assertRaises(base.ParserException, self.check_parser, @@ -536,7 +538,7 @@ class TestUpdateVnfPackage(TestVnfPackage): columns, data = self.update_vnf_package.take_action(parsed_args) self.assertItemsEqual(_get_columns_vnf_package( vnf_package_obj=fake_response, action='update'), columns) - self.assertItemsEqual( + self.assertListItemsEqual( vnf_package_fakes.get_vnf_package_data(fake_response), data) def test_update_no_options(self): diff --git a/tackerclient/tests/unit/osc/v1/vnf_package_fakes.py b/tackerclient/tests/unit/osc/v1/vnf_package_fakes.py index b7967297..b9ad73b6 100644 --- a/tackerclient/tests/unit/osc/v1/vnf_package_fakes.py +++ b/tackerclient/tests/unit/osc/v1/vnf_package_fakes.py @@ -15,6 +15,8 @@ from oslo_utils import uuidutils +from tackerclient.osc.v1.vnfpkgm import vnf_package + def vnf_package_obj(attrs=None, onboarded_state=False): """Create a fake vnf package. @@ -34,7 +36,7 @@ def vnf_package_obj(attrs=None, onboarded_state=False): "onboardingState": "CREATED", "operationalState": "DISABLED", "usageState": "NOT_IN_USE", - "userDefinedData": None} + "userDefinedData": {'key': 'value'}} if onboarded_state: fake_vnf_package = {"id": "60a6ac16-b50d-4e92-964b-b3cf98c7cf5c", @@ -70,7 +72,7 @@ def vnf_package_obj(attrs=None, onboarded_state=False): "onboardingState": "ONBOARDED", "operationalState": "ENABLED", "usageState": "IN_USE", - "userDefinedData": None, + "userDefinedData": {'key': 'value'}, "_links": { "self": { "href": "string" @@ -88,10 +90,10 @@ def vnf_package_obj(attrs=None, onboarded_state=False): return fake_vnf_package -def get_vnf_package_data(vnf_package, **kwargs): +def get_vnf_package_data(vnf_package_obj, **kwargs): """Get the vnf package data from a FakeVnfPackage dict object. - :param vnf_package: + :param vnf_package_obj: A FakeVnfPackage dict object :return: A list which may include the following values: @@ -99,19 +101,27 @@ def get_vnf_package_data(vnf_package, **kwargs): 'vnfd': {'href': 'string'}}, '60a6ac16-b50d-4e92-964b-b3cf98c7cf5c', 'CREATED', 'DISABLED', 'NOT_IN_USE', {'Test_key': 'Test_value'}] """ + complex_attributes = ['softwareImages', 'checksum', '_links', + 'userDefinedData'] + for attribute in complex_attributes: + if vnf_package_obj.get(attribute): + vnf_package_obj.update( + {attribute: vnf_package.FormatComplexDataColumn( + vnf_package_obj[attribute])}) if kwargs.get('list_action'): # In case of List VNF packages we get empty string as data for # 'vnfProductName' if onboardingState is CREATED. Hence to match # up with actual data we are adding here empty string. - if not vnf_package.get('vnfProductName'): - vnf_package['vnfProductName'] = '' + if not vnf_package_obj.get('vnfProductName'): + vnf_package_obj['vnfProductName'] = '' - # return the list of data as per column order if kwargs.get('columns'): - return tuple([vnf_package[key] for key in kwargs.get('columns')]) + # return the list of data as per column order + return tuple([vnf_package_obj[key] for key in kwargs.get('columns')]) - return tuple([vnf_package[key] for key in sorted(vnf_package.keys())]) + return tuple([vnf_package_obj[key] for key in sorted( + vnf_package_obj.keys())]) def create_vnf_packages(count=2, onboarded_vnf_package=False):