From f10e0455f020e621f8cdaac714f9c4f8c8b9dba7 Mon Sep 17 00:00:00 2001 From: albailey Date: Thu, 13 Aug 2020 07:59:54 -0500 Subject: [PATCH] Enabled python3 unit tests in tox and zuul Replaces the unittest2 base module with testtools. Adds py36 unit test target in tox.ini, called from zuul. Updates unit tests to pass when run in both py27 and py36. Add sample CLI unit tests for fw update strategy based on a mixin for update strategy. Story: 2007875 Task: 40674 Change-Id: Ia1b94110a53d48249aed76c94b07f8ffc2946bb3 Signed-off-by: albailey --- .zuul.yaml | 10 +++ .../dcmanagerclient/tests/base.py | 11 +-- .../dcmanagerclient/tests/v1/mixins.py | 72 +++++++++++++++++++ .../tests/v1/test_fw_update_strategy.py | 19 +++++ .../tests/v1/test_subcloud_manager.py | 13 ++-- .../dcmanagerclient/tests/v1/utils.py | 35 +++++++++ distributedcloud-client/test-requirements.txt | 1 - distributedcloud-client/tox.ini | 8 ++- 8 files changed, 156 insertions(+), 13 deletions(-) create mode 100644 distributedcloud-client/dcmanagerclient/tests/v1/mixins.py create mode 100644 distributedcloud-client/dcmanagerclient/tests/v1/test_fw_update_strategy.py create mode 100644 distributedcloud-client/dcmanagerclient/tests/v1/utils.py diff --git a/.zuul.yaml b/.zuul.yaml index 3ac4e20..60e1e2e 100644 --- a/.zuul.yaml +++ b/.zuul.yaml @@ -9,12 +9,14 @@ - openstack-tox-linters - stx-distcloud-client-tox-pep8 - stx-distcloud-client-tox-py27 + - stx-distcloud-client-tox-py36 - stx-distcloud-client-tox-pylint gate: jobs: - openstack-tox-linters - stx-distcloud-client-tox-pep8 - stx-distcloud-client-tox-py27 + - stx-distcloud-client-tox-py36 - stx-distcloud-client-tox-pylint post: jobs: @@ -28,6 +30,14 @@ tox_envlist: py27 tox_extra_args: -c distributedcloud-client/tox.ini +- job: + name: stx-distcloud-client-tox-py36 + parent: tox + description: Run py36 for distcloud-client + vars: + tox_envlist: py36 + tox_extra_args: -c distributedcloud-client/tox.ini + - job: name: stx-distcloud-client-tox-pylint parent: tox diff --git a/distributedcloud-client/dcmanagerclient/tests/base.py b/distributedcloud-client/dcmanagerclient/tests/base.py index 8fb0038..034c805 100644 --- a/distributedcloud-client/dcmanagerclient/tests/base.py +++ b/distributedcloud-client/dcmanagerclient/tests/base.py @@ -21,9 +21,8 @@ # import json - import mock -import unittest2 +import testtools class FakeResponse(object): @@ -39,9 +38,12 @@ class FakeResponse(object): return json.loads(self.content) -class BaseClientTest(unittest2.TestCase): +class BaseClientTest(testtools.TestCase): _client = None + def setUp(self): + super(BaseClientTest, self).setUp() + def mock_http_get(self, content, status_code=200): if isinstance(content, dict): content = json.dumps(content) @@ -76,8 +78,9 @@ class BaseClientTest(unittest2.TestCase): return self._client.http_client.delete -class BaseCommandTest(unittest2.TestCase): +class BaseCommandTest(testtools.TestCase): def setUp(self): + super(BaseCommandTest, self).setUp() self.app = mock.Mock() self.client = self.app.client_manager.subcloud_manager diff --git a/distributedcloud-client/dcmanagerclient/tests/v1/mixins.py b/distributedcloud-client/dcmanagerclient/tests/v1/mixins.py new file mode 100644 index 0000000..1af418d --- /dev/null +++ b/distributedcloud-client/dcmanagerclient/tests/v1/mixins.py @@ -0,0 +1,72 @@ +# +# Copyright (c) 2020 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# +from dcmanagerclient.tests.v1 import utils + + +class UpdateStrategyMixin(object): + """Mixin for testing the different types of dcmanager update strategies. + + Used by concrete testsuites of strategy types such as patch, upgrade, etc.. + Subclasses must: + - mix with BaseCommandTest + - provide: self.sw_update_manager + - provide: self.show_command + """ + def setUp(self): + super(UpdateStrategyMixin, self).setUp() + + def test_create_strategy(self): + """Test that if no strategy exists, one can be created.""" + # prepare mixin attributes + manager_to_test = self.sw_update_manager + expected_strategy_type = manager_to_test.update_type + + # mock the result of the API call + strategy = utils.make_strategy(strategy_type=expected_strategy_type) + + # mock that there is no pre-existing strategy + manager_to_test.create_sw_update_strategy.return_value = strategy + + # invoke the backend method for the CLI. + # Returns a tuple of field descriptions, and a second tuple of values + fields, results = self.call(self.create_command) + + # results is a tuple of expected length 7 + self.assertEqual(len(results), 7) + # result tuple values are + # - strategy_type + # - subcloud_apply_type + # - max_parallel_subclouds + # - stop_on_failure + # - state + # - created_at + # - updated_at + self.assertEqual(results[0], expected_strategy_type) + + def test_get_strategy(self): + # prepare mocked results + manager_to_test = self.sw_update_manager + expected_strategy_type = manager_to_test.update_type + expected_apply_type = 'parallel' + strategy = utils.make_strategy(strategy_type=expected_strategy_type, + subcloud_apply_type=expected_apply_type) + manager_to_test.update_sw_strategy_detail.return_value = strategy + + # invoke the backend method for the CLI. + # Returns a tuple of field descriptions, and a second tuple of values + fields, results = self.call(self.show_command) + # results is a tuple of expected length 7 + self.assertEqual(len(results), 7) + # result tuple values are + # - strategy_type + # - subcloud_apply_type + # - max_parallel_subclouds + # - stop_on_failure + # - state + # - created_at + # - updated_at + self.assertEqual(results[0], expected_strategy_type) + self.assertEqual(results[1], expected_apply_type) diff --git a/distributedcloud-client/dcmanagerclient/tests/v1/test_fw_update_strategy.py b/distributedcloud-client/dcmanagerclient/tests/v1/test_fw_update_strategy.py new file mode 100644 index 0000000..e0130ec --- /dev/null +++ b/distributedcloud-client/dcmanagerclient/tests/v1/test_fw_update_strategy.py @@ -0,0 +1,19 @@ +# +# Copyright (c) 2020 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +from dcmanagerclient.commands.v1 import fw_update_manager as cli_cmd +from dcmanagerclient.tests import base +from dcmanagerclient.tests.v1.mixins import UpdateStrategyMixin + + +class TestFwUpdateStrategy(UpdateStrategyMixin, base.BaseCommandTest): + + def setUp(self): + super(TestFwUpdateStrategy, self).setUp() + self.sw_update_manager = \ + self.app.client_manager.fw_update_manager.fw_update_manager + self.create_command = cli_cmd.CreateFwUpdateStrategy + self.show_command = cli_cmd.ShowFwUpdateStrategy diff --git a/distributedcloud-client/dcmanagerclient/tests/v1/test_subcloud_manager.py b/distributedcloud-client/dcmanagerclient/tests/v1/test_subcloud_manager.py index 7bc38aa..fb185ba 100644 --- a/distributedcloud-client/dcmanagerclient/tests/v1/test_subcloud_manager.py +++ b/distributedcloud-client/dcmanagerclient/tests/v1/test_subcloud_manager.py @@ -199,7 +199,7 @@ class TestCLISubcloudManagerV1(base.BaseCommandTest): "external_oam_floating_address": EXTERNAL_OAM_FLOATING_ADDRESS, } - with tempfile.NamedTemporaryFile() as f: + with tempfile.NamedTemporaryFile(mode='w') as f: yaml.dump(values, f) file_path = os.path.abspath(f.name) actual_call = self.call( @@ -308,10 +308,9 @@ class TestCLISubcloudManagerV1(base.BaseCommandTest): with tempfile.NamedTemporaryFile() as f: file_path = os.path.abspath(f.name) - # Python 2.7 onwards, context manager can be used to get the - # actual Exception object - with self.assertRaises(DCManagerClientException) as context: - self.call(subcloud_cmd.ReconfigSubcloud, - app_args=[ID, '--deploy-config', file_path]) + e = self.assertRaises(DCManagerClientException, + self.call, + subcloud_cmd.ReconfigSubcloud, + app_args=[ID, '--deploy-config', file_path]) self.assertTrue('deploy-config file does not exist' - in str(context.exception)) + in str(e)) diff --git a/distributedcloud-client/dcmanagerclient/tests/v1/utils.py b/distributedcloud-client/dcmanagerclient/tests/v1/utils.py new file mode 100644 index 0000000..23c0c75 --- /dev/null +++ b/distributedcloud-client/dcmanagerclient/tests/v1/utils.py @@ -0,0 +1,35 @@ +# +# Copyright (c) 2020 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +import mock + +from oslo_utils import timeutils + +from dcmanagerclient.api.v1.sw_update_manager import SwUpdateStrategy + +TIME_NOW = timeutils.utcnow().isoformat() +DEFAULT_APPLY_TYPE = 'serial' +DEFAULT_MAX_PARALLEL = 2 +DEFAULT_STATE = 'initial' +DEFAULT_STRATEGY_TYPE = 'patch' + + +def make_strategy(manager=mock.MagicMock(), + strategy_type=DEFAULT_STRATEGY_TYPE, + subcloud_apply_type=DEFAULT_APPLY_TYPE, + max_parallel_subclouds=DEFAULT_MAX_PARALLEL, + stop_on_failure=False, + state=DEFAULT_STATE, + created_at=TIME_NOW, + updated_at=None): + return SwUpdateStrategy(manager, + strategy_type, + subcloud_apply_type, + max_parallel_subclouds, + stop_on_failure, + state, + created_at, + updated_at) diff --git a/distributedcloud-client/test-requirements.txt b/distributedcloud-client/test-requirements.txt index ac7fe13..42a93bb 100644 --- a/distributedcloud-client/test-requirements.txt +++ b/distributedcloud-client/test-requirements.txt @@ -6,7 +6,6 @@ pylint==1.9.2;python_version<"3.0" # GPLv2 pylint==2.3.1;python_version>="3.0" # GPLv2 python-openstackclient>=3.3.0 # Apache-2.0 sphinx>=1.5.1 # BSD -unittest2 # BSD fixtures>=3.0.0 # Apache-2.0/BSD mock>=2.0 # BSD nose # LGPL diff --git a/distributedcloud-client/tox.ini b/distributedcloud-client/tox.ini index ea80fd9..1fcfb95 100644 --- a/distributedcloud-client/tox.ini +++ b/distributedcloud-client/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 2.3 -envlist = py27,pep8,pylint +envlist = py27,py36,pep8,pylint skipsdist = True toxworkdir = /tmp/{env:USER}_dc_client_tox @@ -32,6 +32,12 @@ commands = find {toxinidir} -not -path '{toxinidir}/.tox/*' -name '*.py[c|o]' -delete stestr --test-path={[dcclient]client_base_dir}/dcmanagerclient/tests run '{posargs}' +[testenv:py36] +basepython = python3.6 +commands = + find {toxinidir} -not -path '{toxinidir}/.tox/*' -name '*.py[c|o]' -delete + stestr --test-path={[dcclient]client_base_dir}/dcmanagerclient/tests run '{posargs}' + [testenv:pep8] basepython = python3 commands = flake8 {posargs}