Merge "Improve unit test coverage for dcmanager's orchestrator/states/software"
This commit is contained in:
commit
28903f8bfd
|
@ -198,6 +198,11 @@ class DCManagerTestCase(base.BaseTestCase):
|
|||
self.mock_sysinv_client = mock_patch.start()
|
||||
self.addCleanup(mock_patch.stop)
|
||||
|
||||
def _mock_read_from_cache(self, target):
|
||||
mock_patch = mock.patch.object(target, '_read_from_cache')
|
||||
self.mock_read_from_cache = mock_patch.start()
|
||||
self.addCleanup(mock_patch.stop)
|
||||
|
||||
def _mock_get_network_address_pool(self):
|
||||
"""Mock phased subcloud deploy's get_network_address_pool"""
|
||||
|
||||
|
|
|
@ -3,38 +3,66 @@
|
|||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
import mock
|
||||
|
||||
from dcmanager.common import consts
|
||||
from dcmanager.orchestrator.states.base import BaseState
|
||||
from dcmanager.orchestrator.states.software.finish_strategy import \
|
||||
FinishStrategyState
|
||||
from dcmanager.tests.unit.orchestrator.states.software.test_base import \
|
||||
TestSoftwareOrchestrator
|
||||
|
||||
|
||||
REGION_ONE_RELEASES = {"DC.1": {"sw_version": "20.12",
|
||||
"state": "committed"},
|
||||
"DC.2": {"sw_version": "20.12",
|
||||
"state": "committed"},
|
||||
"DC.3": {"sw_version": "20.12",
|
||||
"state": "committed"},
|
||||
"DC.8": {"sw_version": "20.12",
|
||||
"state": "committed"}}
|
||||
REGION_ONE_RELEASES = {
|
||||
"DC.1": {
|
||||
"sw_version": "20.12",
|
||||
"state": "committed"
|
||||
},
|
||||
"DC.2": {
|
||||
"sw_version": "20.12",
|
||||
"state": "committed"
|
||||
},
|
||||
"DC.3": {
|
||||
"sw_version": "20.12",
|
||||
"state": "committed"
|
||||
},
|
||||
"DC.8": {
|
||||
"sw_version": "20.12",
|
||||
"state": "committed"
|
||||
}
|
||||
}
|
||||
|
||||
SUBCLOUD_RELEASES = {"DC.1": {"sw_version": "20.12",
|
||||
"state": "committed"},
|
||||
"DC.2": {"sw_version": "20.12",
|
||||
"state": "committed"},
|
||||
"DC.3": {"sw_version": "20.12",
|
||||
"state": "deployed"},
|
||||
"DC.9": {"sw_version": "20.12",
|
||||
"state": "available"}}
|
||||
SUBCLOUD_RELEASES = {
|
||||
"DC.1": {
|
||||
"sw_version": "20.12",
|
||||
"state": "committed"
|
||||
},
|
||||
"DC.2": {
|
||||
"sw_version": "20.12",
|
||||
"state": "committed"
|
||||
},
|
||||
"DC.3": {
|
||||
"sw_version": "20.12",
|
||||
"state": "deployed"
|
||||
},
|
||||
"DC.9": {
|
||||
"sw_version": "20.12",
|
||||
"state": "available"
|
||||
},
|
||||
"DC.10": {
|
||||
"sw_version": "20.12",
|
||||
"state": "deployed"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class TestFinishStrategyState(TestSoftwareOrchestrator):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
self._mock_read_from_cache(FinishStrategyState)
|
||||
|
||||
self.on_success_state = consts.STRATEGY_STATE_COMPLETE
|
||||
|
||||
# Add the subcloud being processed by this unit test
|
||||
|
@ -51,10 +79,10 @@ class TestFinishStrategyState(TestSoftwareOrchestrator):
|
|||
self.software_client.commit_patch = mock.MagicMock()
|
||||
self._read_from_cache = mock.MagicMock()
|
||||
|
||||
@mock.patch.object(FinishStrategyState, '_read_from_cache')
|
||||
def test_finish_strategy_success(self, mock_read_from_cache):
|
||||
def test_finish_strategy_success(self):
|
||||
"""Test software finish strategy when the API call succeeds."""
|
||||
mock_read_from_cache.return_value = REGION_ONE_RELEASES
|
||||
|
||||
self.mock_read_from_cache.return_value = REGION_ONE_RELEASES
|
||||
|
||||
self.software_client.query.side_effect = [SUBCLOUD_RELEASES]
|
||||
|
||||
|
@ -71,10 +99,10 @@ class TestFinishStrategyState(TestSoftwareOrchestrator):
|
|||
self.assert_step_updated(self.strategy_step.subcloud_id,
|
||||
self.on_success_state)
|
||||
|
||||
@mock.patch.object(FinishStrategyState, '_read_from_cache')
|
||||
def test_finish_strategy_no_operation_required(self, mock_read_from_cache):
|
||||
def test_finish_strategy_no_operation_required(self):
|
||||
"""Test software finish strategy when no operation is required."""
|
||||
mock_read_from_cache.return_value = REGION_ONE_RELEASES
|
||||
|
||||
self.mock_read_from_cache.return_value = REGION_ONE_RELEASES
|
||||
|
||||
self.software_client.query.side_effect = [REGION_ONE_RELEASES]
|
||||
|
||||
|
@ -88,3 +116,62 @@ class TestFinishStrategyState(TestSoftwareOrchestrator):
|
|||
# On success, the state should transition to the next state
|
||||
self.assert_step_updated(self.strategy_step.subcloud_id,
|
||||
self.on_success_state)
|
||||
|
||||
def test_finish_strategy_fails_when_query_exception(self):
|
||||
"""Test finish strategy fails when software client query raises exception"""
|
||||
|
||||
self.mock_read_from_cache.return_value = REGION_ONE_RELEASES
|
||||
|
||||
self.software_client.query.side_effect = Exception()
|
||||
|
||||
self.worker.perform_state_action(self.strategy_step)
|
||||
|
||||
self.assert_step_updated(
|
||||
self.strategy_step.subcloud_id, consts.STRATEGY_STATE_FAILED
|
||||
)
|
||||
|
||||
def test_finish_strategy_fails_when_delete_exception(self):
|
||||
"""Test finish strategy fails when software client delete raises exception"""
|
||||
|
||||
self.mock_read_from_cache.return_value = REGION_ONE_RELEASES
|
||||
|
||||
self.software_client.query.side_effect = [SUBCLOUD_RELEASES]
|
||||
self.software_client.delete.side_effect = Exception()
|
||||
|
||||
self.worker.perform_state_action(self.strategy_step)
|
||||
|
||||
self.assert_step_updated(
|
||||
self.strategy_step.subcloud_id, consts.STRATEGY_STATE_FAILED
|
||||
)
|
||||
|
||||
@mock.patch.object(BaseState, 'stopped')
|
||||
def test_finish_strategy_fails_when_stopped(self, mock_base_stopped):
|
||||
"""Test finish strategy fails when stopped"""
|
||||
self.mock_read_from_cache.return_value = REGION_ONE_RELEASES
|
||||
|
||||
self.software_client.query.side_effect = [SUBCLOUD_RELEASES]
|
||||
|
||||
mock_base_stopped.return_value = True
|
||||
|
||||
self.worker.perform_state_action(self.strategy_step)
|
||||
|
||||
self.assert_step_updated(
|
||||
self.strategy_step.subcloud_id, consts.STRATEGY_STATE_FAILED
|
||||
)
|
||||
|
||||
def test_finish_strategy_fails_when_commit_patch_exception(self):
|
||||
"""Test finish strategy fails when software client commit_patch
|
||||
|
||||
raises exception
|
||||
"""
|
||||
|
||||
self.mock_read_from_cache.return_value = REGION_ONE_RELEASES
|
||||
|
||||
self.software_client.query.side_effect = [SUBCLOUD_RELEASES]
|
||||
self.software_client.commit_patch.side_effect = Exception()
|
||||
|
||||
self.worker.perform_state_action(self.strategy_step)
|
||||
|
||||
self.assert_step_updated(
|
||||
self.strategy_step.subcloud_id, consts.STRATEGY_STATE_FAILED
|
||||
)
|
||||
|
|
|
@ -6,7 +6,9 @@
|
|||
|
||||
import mock
|
||||
|
||||
from dccommon import consts as dccommon_consts
|
||||
from dcmanager.common import consts
|
||||
from dcmanager.db import api as db_api
|
||||
from dcmanager.tests.unit.orchestrator.states.software.test_base import \
|
||||
TestSoftwareOrchestrator
|
||||
|
||||
|
@ -15,6 +17,8 @@ MISSING_LICENSE_RESPONSE = {
|
|||
"error": "License file not found. A license may not have been installed.",
|
||||
}
|
||||
|
||||
GENERIC_ERROR_RESPONSE = {"content": "", "error": "Invalid license"}
|
||||
|
||||
LICENSE_VALID_RESPONSE = {"content": "A valid license", "error": ""}
|
||||
|
||||
ALTERNATE_LICENSE_RESPONSE = {"content": "A different valid license", "error": ""}
|
||||
|
@ -69,7 +73,7 @@ class TestInstallLicenseState(TestSoftwareOrchestrator):
|
|||
self.strategy_step.subcloud_id, consts.STRATEGY_STATE_FAILED
|
||||
)
|
||||
|
||||
def test_install_license_success(self):
|
||||
def test_install_license_succeeds(self):
|
||||
"""Test the install license step succeeds.
|
||||
|
||||
The license will be installed on the subcloud when system controller
|
||||
|
@ -147,8 +151,8 @@ class TestInstallLicenseState(TestSoftwareOrchestrator):
|
|||
self.strategy_step.subcloud_id, self.on_success_state
|
||||
)
|
||||
|
||||
def test_install_license_skip_when_no_sys_controller_lic(self):
|
||||
"""Test license install skipped when no license on system controller."""
|
||||
def test_install_license_skips_with_sys_controller_without_license(self):
|
||||
"""Test license install skips when sys controller doesn't have a license"""
|
||||
|
||||
# Only makes one query: to system controller
|
||||
self.sysinv_client.get_license.return_value = MISSING_LICENSE_RESPONSE
|
||||
|
@ -163,3 +167,28 @@ class TestInstallLicenseState(TestSoftwareOrchestrator):
|
|||
self.assert_step_updated(
|
||||
self.strategy_step.subcloud_id, self.on_success_state
|
||||
)
|
||||
|
||||
def test_install_license_fails_with_generic_error_response(self):
|
||||
"""Test license install fails with generic error response"""
|
||||
|
||||
# Only makes one query: to system controller
|
||||
self.sysinv_client.get_license.return_value = GENERIC_ERROR_RESPONSE
|
||||
|
||||
# invoke the strategy state operation on the orch thread
|
||||
self.worker.perform_state_action(self.strategy_step)
|
||||
|
||||
subcloud = db_api.subcloud_get(self.ctx, self.subcloud.id)
|
||||
|
||||
self.assertEqual(
|
||||
subcloud.error_description, "An unexpected error occurred querying the "
|
||||
f"license {dccommon_consts.SYSTEM_CONTROLLER_NAME}. "
|
||||
f"Detail: {GENERIC_ERROR_RESPONSE['error']}"
|
||||
)
|
||||
|
||||
# Should skip install_license API call
|
||||
self.sysinv_client.install_license.assert_not_called()
|
||||
|
||||
# Verify it successfully moves to the next step
|
||||
self.assert_step_updated(
|
||||
self.strategy_step.subcloud_id, consts.STRATEGY_STATE_FAILED
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue