From 2939ed85bdcc73b1a061e5a0ad0eb9fa90fe1f09 Mon Sep 17 00:00:00 2001 From: Jiri Podivin Date: Wed, 23 Jun 2021 13:34:18 +0200 Subject: [PATCH] New test case and documentation for the export_stack function. New test case for handling a decoding error encountered while reading a file. Function documentation moved to docstring from comment, and expanded to cover necessary API and implementation facts. Too general 'Exception', raised if there are no data to export for the specific key, was changed to 'RuntimeError'. Some vars were renamed in order to improve readability. Signed-off-by: Jiri Podivin Change-Id: I04f8eb15e58a2bec125f5de23ec2da7e51454e1c --- tripleoclient/export.py | 42 +++++++++++++++++++++++------- tripleoclient/tests/test_export.py | 21 +++++++++++++++ 2 files changed, 53 insertions(+), 10 deletions(-) diff --git a/tripleoclient/export.py b/tripleoclient/export.py index 7676a53e1..1ad53d242 100644 --- a/tripleoclient/export.py +++ b/tripleoclient/export.py @@ -64,35 +64,57 @@ def export_passwords(heat, stack, excludes=True): def export_stack(heat, stack, should_filter=False, config_download_dir=constants.DEFAULT_WORK_DIR): + """Export stack information. + Iterates over parameters selected for export and loads + additional data from the referenced files. - # data to export - # parameter: Parameter to be exported - # file: IF file specified it is taken as source instead of heat - # output.File is relative to /stack. - # filter: in case only specific settings should be - # exported from parameter data. + :param heat: tht client + :type heat: Client + :param stack: stack name for password generator + :type stack: string + :params should_filter: + should the export only include values with keys + defined in the 'filter' list. Defaults to `False` + :type should_filter: bool + :param config_download_dir: + path to download directory, + defaults to `constants.DEFAULT_WORK_DIR` + :type config_download_dir: string + + :returns: data to export + :rtype: dict + + The function detetermines what data to export using information, + obtained from the preset `tripleoclient.constants.EXPORT_DATA` dictionary. + parameter: Parameter to be exported + file: If file is specified it is taken as source instead of heat + output. File is relative to /stack. + filter: in case only specific settings should be + exported from parameter data. + """ data = {} heat_stack = oooutils.get_stack(heat, stack) for export_key, export_param in constants.EXPORT_DATA.items(): param = export_param["parameter"] + if "file" in export_param: # get file data file = os.path.join(config_download_dir, stack, export_param["file"]) + if not os.path.exists(file): LOG.warning('File %s was not found during export' % file) - with open(file, 'r') as ff: + with open(file, 'r') as parameter_file: try: - export_data = json.load(ff) + export_data = json.load(parameter_file) except (TypeError, json.JSONDecodeError) as e: LOG.error( _('Could not read file %s') % file) LOG.error(e) - else: # get stack data export_data = oooutils.get_stack_output_item( @@ -110,7 +132,7 @@ def export_stack(heat, stack, should_filter=False, data[param] = export_data else: - raise Exception( + raise RuntimeError( "No data returned to export %s from." % param) return data diff --git a/tripleoclient/tests/test_export.py b/tripleoclient/tests/test_export.py index ad1f61c81..b34018e44 100644 --- a/tripleoclient/tests/test_export.py +++ b/tripleoclient/tests/test_export.py @@ -12,6 +12,7 @@ # License for the specific language governing permissions and limitations # under the License. # +from json.decoder import JSONDecodeError import os import mock @@ -134,6 +135,26 @@ class TestExport(TestCase): export.export_stack(heat, "control") mock_get_stack.assert_called_once_with(heat, 'control') + @mock.patch('tripleoclient.export.LOG.error', autospec=True) + @mock.patch('tripleoclient.export.json.load', autospec=True, + side_effect=JSONDecodeError) + @mock.patch('tripleoclient.export.open') + @mock.patch('tripleoclient.export.os.path.exists', autospec=True, + return_value=True) + @mock.patch('tripleoclient.utils.get_stack', autospec=True) + def test_export_stack_decode_error(self, mock_get_stack, mock_exists, + mock_open, mock_json_load, mock_log): + + heat = mock.MagicMock() + mock_get_stack.return_value = self.mock_stack + export.export_stack(heat, "overcloud") + + mock_open.assert_called_once_with( + os.path.join( + os.environ.get('HOME'), + 'config-download/overcloud/group_vars/overcloud.json'), + 'r') + @mock.patch('tripleoclient.export.LOG') @mock.patch('tripleo_common.utils.plan.generate_passwords') def test_export_passwords(self, mock_gen_pass, mock_log):